Aloha Editor

Aloha Editor Guides

These guides help you to make your content editable and to develop Aloha Editor.

The Repository API

After reading this guide, you will

  • Understand the concept
  • Repository item data structure
  • Know how to configure the Repository Manager
  • Know how to implementing the Repository API

1 Concept

A repository is a service or data source, which provides repository items and is registered with the Repository Manager (RepositoryManager). The Repository Manger manages all available repositories and routes queries to all registered repositories. Any plugin may make requests to the Repository Manager for repository items, and specify one or more kinds of items it wishes to have returned, such as website or localanchor (where localanchor could be a headline provided by a document repository implementation). Usually a CMS back-end would provide data such as links to sites, images, videos, files that should be available during the editing process. The repository data are repository items that contain JSON data with at least the following attributes: id, name, url, type. All other attributes are optional and depend on the item’s type. A repository may provide repository items of a freely definable type. We suggest type to be a mimetype, e.g.: image/png, text/html, video/H264, application/pdf …. However, this is not required.

1.1 Origins

Aloha Editor’s Repository API is based on the CMIS specification.

Notable differences are:

2 Repository item data structure

The API and data layout is inspired by CMIS.

2.1 Repository Item types

The object concept from CMIS is inconsistent and too complicated for Aloha Editor’s needs. So we opted for a much simpler model, which is easier to use for developers (but still allows one to implement CMIS if desirable).

2.1.1 type, baseType and mimeType Each repository item must have at least the type attribute defined, but may optionally also have a mimeType attribute defined. See below for more details.

Besides type being required, baseType is also required. baseType must be either document or folder. That indeed means that you can “subclass” document and folder to fullfill your domain-specific or site-specific needs. Note that you can not set baseType to anything else than document or folder — from an OOP point of view, this implies that you can only do single level inheritance, not multiple levels of inheritance.

folder is used only for browsing your repository, and it probably makes less sense to define your own, more specific type for type = folder repository items. An example could be that each user in your system has his own folder with content, so you could then define a ownFolder, so this one could be styled differently in the repository browser.

However, for type = document repository items, it makes a lot of sense: documents are the actual content your users are looking for; it’s the whole reason the Repository API exists. Many different types of content likely exist: videos, audio, text, rich text, vector graphics, photographs, and so on. You could define type to be equal to the mimetype. But you could also come up with your own types to discern between repository items that have the same mimeType, such as internalImage for images that are part of your site/CMS, flickrImage for external images hosted by Flickr, and externalImage for other externally hosted images.

2.1.2 Document
  • id REQUIRED
  • repositoryId REQUIRED
  • name REQUIRED
  • baseType REQUIRED (document|folder)
  • type REQUIRED — This is the type you can freely define.
  • parentId OPTIONAL
  • renditions OPTIONAL
  • localName OPTIONAL
  • createdBy OPTIONAL
  • creationDate OPTIONAL
  • lastModifiedBy OPTIONAL
  • lastModificationDate OPTIONAL
  • length OPTIONAL
  • mimeType OPTIONAL
  • fileName OPTIONAL
  • url OPTIONAL
2.1.3 Folder
  • id REQUIRED
  • repositoryId REQUIRED
  • name REQUIRED
  • baseType REQUIRED (document|folder)
  • type REQUIRED
  • parentId REQUIRED
  • localName OPTIONAL
  • createdBy OPTIONAL
  • creationDate OPTIONAL
  • lastModifiedBy OPTIONAL
  • lastModificationDate OPTIONAL

2.2 Repository Item Renditions

For some type = document repository items, it makes sense to have multiple representations. For example, for rich text documents, you could have .rtf, .docx, .odf and pdf renditions (or representations or renderings or derivatives or variations or … inaccurately, but often used: versions). Another example: a vector graphics file in both svg and pdf format.

The most archetypical example is probably the case of images: you typically have the “original” image, of which many derivatives are generated: a medium version, a small version and a thumbnail. These call all be renditions!

A more complete example: a page document in a repository may be rendered in 3 different languages. Each of these 3 variations of that page can be served by the repository as a rendition of any of the other 2 translations that correspond with it. Each of these pages may be a stand-alone document in the repository as well. In fact, different renditions for a single document type will likely be different files which the repository will serve back in response to a request for a specific rendition of a given object.

No matter what your renditions (and there is no limit on their number) turn out to be, you can assign it your own naming scheme, so that you can make it fit your needs. The name of a rendition is called its kind.

2.2.1 Rendition
  • documentId ID REQUIRED identifies the rendition document (The baseType must be document)
  • url URL REQUIRED identifies the rendition stream.
  • mimeType String REQUIRED The MIME type of the rendition stream.
  • filename String REQUIRED The filename of the rendition stream
  • length Integer OPTIONAL The length of the rendition stream in bytes.
  • name String OPTIONAL Human readable information about the rendition.
  • kind String REQUIRED A categorization associated with the rendition. This is freely definable. An example could be:
    • square – an image square 75×75
    • thumbnail – a thumbnail version of the object
    • small – 240 on longest side
    • medium- 500 on longest side
    • large – 1024 on longest side (only exists for very large original images)
    • docx – Microsoft docx Version of the content
    • lang_de – same content in German language
    • lang_fr – same content in French language
    • pdf – pdf version of the content
  • height Integer OPTIONAL Typically used for image type renditions (expressed as pixels). SHOULD be present if kind equals thumbnail.
  • width Integer OPTIONAL Typically used for image type renditions (expressed as pixels). SHOULD be present if kind equals thumbnail.
2.2.2 Example: Flickr Image Repository Item
  • id – gailenejane/5008283282
  • name – Quiet moment
  • baseType – document
  • type – image
  • url http://www.flickr.com/photos/gailenejane/5008283282/

The JSON response could look like:


{
id: 'gailenejane/5008283282’,
repositoryId: 'flickr',
name: 'Quiet moment’,
type: ‘image/jpeg’,
url: 'http://www.flickr.com/photos/gailenejane/5008283282/‘,
renditions: [{
  url: 'http://farm5.static.flickr.com/4128/5008283282_f3162bc6b7_s.jpg’,
  mimeType: ‘image/jpeg’,
  filename: '4128/5008283282_f3162bc6b7_s.jpg’,
  kind: ’thumbnail’,
  height: 75,
  width: 75
  }]
}

3 Repository API

3.1 query

The implementation should perform a full text search on all attributes and properties of the repository items.

query() receives two parameters: p, which contains all the parameters the query should take into account (if it supports them), and callback, which should be called whenever the results of the query are available.

3.1.1 Parameters

Parameters are passed as properties of p.

Required parameters:

  • queryString [String]

Optional parameters:

  • filter [array] OPTIONAL Attributes that will be returned.
  • orderBy [array] OPTIONAL e.g. [{lastModificationDate: 'DESC', name: 'ASC'}]
  • maxItems [Integer] OPTIONAL
  • inFolderId [RepositoryItem] OPTIONAL This is a predicate function that tests whether or not a candidate object is a child-object of the folder object identified by the given inFolderId.
  • inTreeId [RepositoryItem] OPTIONAL This is a predicate function that tests whether or not a candidate object is a descendant-object of the folder object identified by the given inTreeId.
  • skipCount [Integer] OPTIONAL This is tricky in a merged multi repository scenario.
  • renditionFilter [array] OPTIONAL An array of zero or more type s and kind s; if empty, then all renditions are returned.
3.1.2 Return values

Required return values:

  • objects [Object][] Array of Aloha objects as result of a full text search.
  • hasMoreItems Boolean

Optional return values:

  • numItems [Integer] OPTIONAL

3.2 getChildren

3.2.1 Input attributes
  • folderId [RepositoryItem] OPTIONAL If null the root folderId should be used
  • maxItems [Integer] OPTIONAL
  • skipCount [Integer] OPTIONAL This is tricky in a merged multi repository scenario
  • filter [array] OPTIONAL Attributes that will be returned
  • renditionFilter [array] OPTIONAL
    • Instead of termlist an array of ’’’kind’’’ or ’’’mimetype’’’ is expected. If ’’’null’’’ or ’’’array.length == 0’’’ all renditions are returned. See http://docs.oasis-open.org/cmis/CMIS/v1.0/cd04/cmis-spec-v1.0.html#_Ref237323310
3.2.2 Output attributes
  • [array] Objects Aloha objects as result of a full text search
  • Boolean hasMoreItems
  • Integer numItems OPTIONAL

3.3 getObjectById

3.4 markObject

3.5 makeClean

3.6 example


/**
 * Create the Aloha Repositories object.
 */
define(
[ 'aloha', 'jquery' ],
function ( Aloha, jQuery ) {
	'use strict';
	
	new ( Aloha.AbstractRepository.extend( {
		
		_constructor: function () {
			this._super( 'myRepository' );
		},
				
		/**
		 * initialize the repository
		 */
		init: function () {	},
		
		
		/** 
		 * Searches a repository for repository items matching queryString if none found returns null.
		 * The returned repository items must be an array of Aloha.Repository.Object
		 * 
		 * @param {object} params object with properties
		 * @param {function} callback this method must be called with all resulting repository items
		 */
		query: function ( p, callback ) {
			callback.call( this, [
			     {
			    	 id: 1,
			    	 name: 'My item',
			    	 url: 'http://mydomain.com/myItem.html',
			    	 type: 'text/html'
			     }
			]);
		},
		
		/**
		 * Returns all children of a given motherId.
		 * 
		 * @param {object} params object with properties
		 * @property {array} objectTypeFilter OPTIONAL Object types that will be returned.
		 * @property {array} filter OPTIONAL Attributes that will be returned.
		 * @property {string} inFolderId OPTIONAL his is a predicate function that tests whether or not a candidate object is a child-object of the folder object identified by the given inFolderId (objectId).
		 * @property {array} orderBy OPTIONAL ex. [{lastModificationDate:’DESC’}, {name:’ASC’}]
		 * @property {Integer} maxItems OPTIONAL number items to return as result
		 * @property {Integer} skipCount OPTIONAL This is tricky in a merged multi repository scenario
		 * @property {array} renditionFilter OPTIONAL Instead of termlist an array of kind or mimetype is expected. If null or array.length == 0 all renditions are returned. See http://docs.oasis-open.org/cmis/CMIS/v1.0/cd04/cmis-spec-v1.0.html#_Ref237323310 for renditionFilter
		 * @param {function} callback this method must be called with all resulting repository items
		 */
		getChildren: function ( p, callback ) {
			callback.call( this, [
 			     {
 			    	 id: 1,
 			    	 name: 'My item',
 			    	 url: 'http://mydomain.com/myItem.html',
 			    	 type: 'text/html'
 			     }
 			]);
		},
				
		/**
		 * Get the repositoryItem with given id
		 * Callback: {Aloha.Repository.Object} item with given id
		 * @param itemId {String} id of the repository item to fetch
		 * @param callback {function} callback function
		 */
		getObjectById: function ( itemId, callback ) {
			callback.call( this, [
  			     {
  			    	 id: 1,
  			    	 name: 'My item',
  			    	 url: 'http://mydomain.com/myItem.html',
  			    	 type: 'text/html'
  			     }
  			]);
		},
		
		/**
		 * Mark or modify an object as needed by that repository for handling, processing or identification.
		 * Objects can be any DOM object as A, SPAN, ABBR, etc..
		 * (see http://dev.w3.org/html5/spec/elements.html#embedding-custom-non-visible-data)
		 * @param obj jQuery object to make clean
		 * @return void
		 */
		markObject: function (obj, repositoryItem) {
			obj.attr('data-myRepository-temporary-data').text( repositoryItem.name );
		},

		/**
		 * Make the given jQuery object (representing an object marked as object of this type)
		 * clean. All attributes needed for handling should be removed. 
		 * @param {jQuery} obj jQuery object to make clean
		 * @return void
		 */
		makeClean: function ( obj ) {
			obj.removeAttr('data-myRepository-temporary-data');
		};

	}))(); 

});

4 Reccomandation of repository item attributes

The API and data layout is inspired by CMIS.

4.1 ObjectTypes

The object concept from CMIS is inconsistent and to complicated for Aloha Editors needs. So we changed to a much simpler model, which allows to implement CMIS, but is easier to use for developers. CMIS objects

There are 2 BaseTypes: document and folder. All other objectTypes may extend either document or folder. Extended Objects may not be extended any more.

4.2 Document

  • id MUST
  • repositoryId MUST
  • name MUST
  • baseType MUST (document|folder)
  • type MUST
  • parentId OPTIONAL
  • renditions OPTIONAL
  • localName OPTIONAL
  • createdBy OPTIONAL
  • creationDate OPTIONAL
  • lastModifiedBy OPTIONAL
  • lastModificationDate OPTIONAL
  • length OPTIONAL
  • mimeType OPTIONAL
  • fileName OPTIONAL
  • url OPTIONAL

4.3 Folder

  • id MUST
  • repositoryId MUST
  • name MUST
  • baseType MUST (document|folder)
  • type MUST
  • parentId MUST
  • localName OPTIONAL
  • createdBy OPTIONAL
  • creationDate OPTIONAL
  • lastModifiedBy OPTIONAL
  • lastModificationDate OPTIONAL
  • children OPTIONAL (array of child folders objects)

4.4 Rendition

  • documentId ID identfies the rendition document (baseObjectType == document)
  • url URL identifies the rendition stream.
  • mimeType String The MIME type of the rendition stream.
  • filename String The filename of the rendition stream
  • length Integer (optional)The length of the rendition stream in bytes.
  • name String (optional) Human readable information about the rendition.
  • kind String A categorization String associated with the rendition.
    • square – an image square 75×75
    • thumbnail – a thumbnail version of the object
    • small - 240 on longest side
    • medium- 500 on longest side
    • large – 1024 on longest side (only exists for very large original images)
    • docx – Microsoft docx Version of the content
    • lang_de – same content in german language
    • lang_fr – same content in frensh language
    • pdf – pdf version of the content
  • height Integer (optional) Typically used for ‘image’ renditions (expressed as pixels). SHOULD be present if kind = cmis:thumbnail.
  • width Integer (optional) Typically used for ‘image’ renditions (expressed as pixels). SHOULD be present if kind = cmis:thumbnail.
4.4.1 What are renditions, and why are they so useful?

A repository may implement renditions for any object that has “document” as its baseObjectType. A rendition is simply an alternative representation (rendering) of a given object. Any document may have any number of renditions. For example: A page document in a repositroy may be rendered in 3 different languages. Each of these 3 variations of that page can be served by the repository as a rendition of any of the other 2 translations that correspond with it. Each of these pages may be a stand-alone document in the repository as well. In fact, different renditions for a single document type will likely be different files which the repository will server back in response to a request for a specific rendition of a given object.

5 Configuring the Repository Manager

You may define a timeout (in milliseconds) when the Repository Manager should stop waiting for any repository implementation’s response.


var Aloha = {
	settings : {
		repositories: {
			timeout: 10000 // default 5000 (5 sec)
		}
	}
};

If you want to figure out the optimal value for your timeout, you should test the server-side script for your repository to find its typical response times under heavy load. After determining the maximum time it takes to load a result you might want to add a buffer (e.g. 2–5 seconds) to allow for adapting to even higher server load.