Spirits

Spirits are javascript objects much like widgets and components, but with a less generic name. A spirit is always associated to an element.

Spirits are configured with a number of plugins that facilitate useful stuff you can do with the spirit. For example, the spirit has a plugin named event that handles event listeners and another named dom that handles DOM manipulation.

Summoning spirits

If you need to fetch a spirit out of nowhere, you should never create a new Spirit(), since this only creates the JavaScript object. Use instead Spirit.summon(), which also creates the element.

var spirit = gui.Spirit.summon();
spirit.dom.appendTo(document.body);

This creates a DIV associated to a gui.Spirit, the most basic spirit you can imagine. The dom plugin also features an appearance here.

Channeling spirits

Most often you wouldn't create spirits like this, but instead channel the spirit through a CSS selector, like through a classname.

gui.channel('.gui-spirit', gui.Spirit);

This will make the spirit exist without special API calls whenever something with this classname is found on the page, whether it was there when the page loaded or somebody put it there. From now on, you only have to remember the classname.

It's an ambition for spirits to initialize without special APIs in order to blend in with other frameworks. You can read about current limitations to this strategy.

When channeling spirits, it's important that you do so in an ordered manner. The rule is to declare special cases before general cases.

gui.channel('button.special', SpecialButtonSpirit);
gui.channel('button', ButtonSpirit);

In this example, SpecialButtonSpirit would never exist if the declaration order was reversed, because the match for button would alwys return a hit before button.special was evaluated. Later we'll introduce the concept of modules as a convenient place to channel spirits.

Inlining spirits

You can also channel the spirit inline via the gui attribute. That's not always practical when you decide to rename or remove the spirit, but sometimes it's more important to make the association explicit.

<h1 gui="MySpirit"></h1>

If you prefer data-gui or something else, there's a way to configure the attribute name (citation needed).

Creating spirits

The framework doesn't come with any widgets out of the box, so you will have to create your own. Spirits employ a classical inhertitance model with concepts such as subclasses and super methods. This pattern is fit for GUI components and it is relatively easy to explain, like we just did. To create a spirit, you simply extend an existing spirit. The base spirit is gui.Spirit.

var MySpirit = gui.Spirit.extend({
	onenter: function() {
		this.super.onenter();
		this.dom.text('Hello World');
	}
});

You can channel the spirit into H1 elements like this.

gui.channel('h1', MySpirit);

To make sure that the spririt is alwas assocaited to a h1 element, you can hardcode one into the summon method, which otherwise defaults to a DIV.

var MySpirit = gui.Spirit.extend({
	text: null,
	onenter: function() {
		this.super.onenter();
		this.dom.text(this.text || 'Hello World');
	}
}, {
	summon: function(text) {
		var spirit = this.possess(
			document.createElement('h1')
		);
		spirit.text = text;
		return spirit;
	}
});

We've added a second argument to the extend method. The first configures the spirit instance object, the prototype of the spirit. The second configures static methods, they belong to the spirits constructor object.

We have declared the MySpirit.summon method. You can add any number of arguments to this method. In our example, we've added support for the header text. Unless we overwrite it, the summon method gets copied onto any subclasses of our new class. Read more about classes.

When the spirit enters the document, it will inject a textnode into it's element. This happens at DOMContentLoaded or as soon as the element gets appended somewhere. There are other important events in the life of a spirit and you can simplify your code if you study the spirit lifecycle for a moment.