Spirits
Spirits are javascript objects much like widgets and components, but with a less generic name. A spirit is always associated to an element.
gui.get(element)
returns the spirit associated to that element.- The spirit has a property
element
that points to the 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.
- The spirit has a property
[name]
that points to the plugin. - The plugin has a property
spirit
that points to the spirit.
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.
- In the instance block, the
this
keyword point to the spirit. - In the static block, the
this
keyword point to the constructor.
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.