Aloha Editor

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

JavaScript Style Guide

After reading this guide, you will be able to:

  • Follow our naming conventions for files, variables and types.
  • Use RequireJS in a clean way.
  • Write clean JavaScript code that looks good.

1 Code Conventions

The current codebase does not yet follow all of these principles.

If you checkout Aloha Editor from github you can use bin/lint.sh to check the code with jslint

We follow all suggestions in the jQuery coding style guide

  • We use only the TAB character for indentation.
  • We use UpperCamelCase for class names, and lowerCamelCase for method and property names.
  • Methods and properties that begin with an underscore (_) are private.
  • We use variable names that indicate the content of a variable.


	var MyObject = Class.extend({
		// GOOD
		var myObject = this;
		setTimeout( function() {
			console.log( myObject.name + ' done.' );
		};
		// BAD
		var that = this;
		setTimeout( function() {
			console.log( that.name + ' done.' );
		};
	});

2 Code Documentation

We use JSDoc for code documentation. Please see plugins/common/block/ for an example on how to use this.

Further information about rendering documentation can be found in the Documentation Guide.

3 RequireJS module skeleton

All files which are RequireJS modules (scripts in package/lib) should follow this structure.

package/lib/module.js

/*!
 * Aloha Editor
 * Author & Copyright (c) 2011 Gentics Software GmbH
 * aloha-sales@gentics.com
 * Licensed unter the terms of http://www.aloha-editor.com/license.html
 */

define(['dependency'],
function(Dependency) {
	"use strict";

	// Declare exports

	return exports;
});

4 Classes and Extension Mechanisms

We use the class definition syntax of John Resig – slightly adjusted. This means you can create a new class with Class.extend({ ....}).

The following example shows how to create and instanciate a class, and how the constructor (which must be named _construct()) is called.


var Greeter = Class.extend({
    name: null,

    _constructor: function(name) {
        this.name = name;
    },

    greet: function() {
        alert('Good Morning ' + this.name);
    }
});
var greeterInstance = new Greeter('Christopher');
greeterInstance.greet(); // alerts "Good Morning Chistopher"

Now, if we want to subclass Greeter, this is very easy: Just use Greeter.extend for that:


var GreeterForMen = Greeter.extend({
	_constructor: function(name) {
		this._super('Mr. ' + name);
	}
});
var greeterInstance = new GreeterForMen('Christopher');
greeterInstance.greet(); // alerts "Good Morning Mr. Chistopher"

You can use this._super() to call the superclass constructor.

5 Mixin Support

Our class definition also supports mixins, so you can specify multiple arguments to Class.extend. For example, in order to make your class observable, you can mix in core/mixin.Observable:

The following code is not yet correct; it is however the way we want to change Aloha core.


define(
['core/mixin'],
function(mixin) {
    "use strict";

    return Class.extend(mixin.Observable, {
    	// your methods here
    });
});

A mixin itself should not use Class.extend, but instead just return a simple object. You see this in the following example:

core/observable.js

define(
[],
function() {
	"use strict";
	var exports = {};

	exports.Observable = {
		bind: function(eventType, handler, scope) {
			// implement method here
		},
		trigger: function(eventType) {
			// implement method here
		}
	};

	return exports;
});

For a list of current mixins, you can soon check the API doc. Right now, there is only Observable.

6 Classes

Not current anymore, we strive for a more JS – style.

Every class should go into one module which means one file. The filename should be lowercase, even if the class is camelcased.

package/lib/classname.js

/*!
 * Aloha Editor
 * Author & Copyright (c) 2011 Gentics Software GmbH
 * aloha-sales@gentics.com
 * Licensed unter the terms of http://www.aloha-editor.com/license.html
 */

define(['core/observable'],
function(Observable) {
	"use strict";

	/**
	 * Description of the class
	 *
	 * @class MyClass
	 */
	return Class.extend(Observable, {

		/**
		 * An optional constructor
		 *
		 * @method
		 * @constructor
		 */
		 _constructor: function() {

		 }

	});
});

But a module is not limited to expose a class. You could also export one of the following:

  • Singletons (Class instances)
  • Mixins (Class definition without Class.extend call)

Or just about any other JavaScript value that is useful as a dependency.

7 Singletons

All singletons should follow this structure:


/*!
 * Aloha Editor
 * Author & Copyright (c) 2011 Gentics Software GmbH
 * aloha-sales@gentics.com
 * Licensed unter the terms of http://www.aloha-editor.com/license.html
 */

define([],
function() {
	"use strict";
	
	var component = Class.extend({
		// Class definition here
	});
	
	return new component();
});

It will define a class and return a new instance that will be exported. Singletons are useful for global objects that have state.

8 RequireJS Dependency Order

TODO: Explain the order

  • The base class
  • Other Classes
  • i18n
  • i18nCore
  • Text files
  • vendor
  • css

9 Public API, Private methods and attributes

All methods and properties which are public API are marked with @api. The public API is supported for a longer period by the Aloha Core Team, and when a public API changes, this is clearly communicated in the Release Notes of a version.

On the contrary, we prefix private methods and attributes with an underscore. The user of an API should never override or call methods private methods as they are not meant for him to be overridden.

There’s also a type in between: methods which are not private but do not have a @api annotation. They can be safely overridden by the user, and he should not experience any unwanted behavior. Still, the names or functionality of these methods can change without notice between releases. In the long run, all of these methods should become part of the public API, as soon as they are proven in real life.

To sum it up, we have three types of methods/properties:

  • @api methods: Public API, the user of the object can rely on the functionality to be stable, changes in @api are clearly communicated
  • non-@api but also not private: The user can use it, but needs to be aware the method might still change.
  • private (prefixed with _): The user should never ever call or access this. Very strange things might happen.

10 Naming of methods

10.1 Initialization Methods

Initialization methods should be named init().

Good:

  • init()
  • initSidebar()

Bad:

  • initialize()
  • initializeSidebar()
  • start()
  • run()

10.2 Shutdown methods

Shutdown methods should be named destroy().

Good:

  • destroy()

Bad:

  • shutdown()
  • stop()

11 Changelog