Spark is a JavaScript web application framework inspired by the great framework EmberJS. Spark, however, is aimed at lazy programmers who don't like long method names or don't want to follow a predefined naming convention.
Please see the wiki for complete documentation.
The basic building block of Spark is the Spark.Object
class. It provides a simple interface for
getting and setting observable properties as well as creating subclasses. New Spark.Object
instances are created using the method Spark.Object.new
. It takes as its parameter an optional
Object
containing the new Spark.Object
's default properties.
var fred = Spark.Object.new( { name : 'Fred', age : 42 } );
You can get or set properties on a Spark.Object
by simply calling it as a function, passing the
property name as the first parameter, and the value as the second (or no value at all if you want to
get the current value). Checking for the existance of a property can be done with the method
Spark.Object.has
.
fred( 'age' ); // => 42
fred( 'occupation', 'Marketing' ); // => fred
fred.has( 'occupation' ); // => true
fred.has( 'hair' ); // => false
Unless otherwise noted, all Spark.Object
methods return themselves for chaining.
fred( 'height' : '5\'7"' )( 'height' ); // => 5'7"
You can also get and set properties using the Spark.Object.get
and Spark.Object.set
methods.
Spark.Object.set
has the benefit of being able to take an Object
as its first and only parameter
instead of a name-value pair to set multiple values at once.
fred.set( 'ethnicity', 'Korean' ); // => fred
fred.set({ location : 'San Francisco', gender : 'male' }); // => fred
fred.get( 'location' ); // => San Francisco
All properties on a Spark.Object
can be observed for changes by passing a property name and
callback to Spark.Object.on
. Observers will be called on the next tick of the browser's event
loop and will only be called once per call stack.
fred.on( 'change.spark', 'age', function(){ alert( 'Happy Birthday!' ); } ); // => fred
// This only causes the alert to happen once.
fred.increment( 'age' )
.increment( 'age' ); // => fred
// The alert will be triggered each time the interval fires (once per year).
setInterval(function(){
fred.increment( 'age' );
}, 1000 * 60 * 60 * 24 * 365 ); // One year in milliseconds
You can also observe the Spark.Object
itself by not passing a property name to Spark.Object.on
.
This will result in the callback being called whenever any properties are added, removed, or changed
on the Spark.Object
instance.
Properties can be removed by using the Spark.Object.delete
method. If no property name is provided
all properties are removed and the Spark.Object
destroys itself.
fred.has( 'occupation' ); // => true
fred.delete( 'occupation' ); // => fred
fred.has( 'occupation' ); // => false
fred.delete(); // => undefined
// Fred no longer exists as a `Spark.Object`. Any attempts to use it as a `Spark.Object` after
// deleting it will result in an error.
Subclassing Spark.Object
is very easy, just pass the subclass' constructor to the static method
Spark.Object.extend
. The subclass will have the static members extend
and new
added for you
and the subclass' prototype will be extended with Spark.Object
's prototype and returned.
function Person( name, age ){
this.set({ name : name, age : age });
}
Spark.Object.extend( Person ); // => Person.prototype
var fred = Person.new( 'Fred', 42 );
fred( 'age' ); // => 42
Spark includes browser-side templating with Jade. These
templates are managed with Spark.View
. The Spark.View.new
method takes 3 parameters: a template
string, a jQuery selector, and an Object
of local variables. The selector and locals are both
optional. If a selector is provided the view will insert itself into the DOM using that selector.
The locals Object
will be passed to Jade for rendering the template.
var template = 'h1 Hello World!';
var view = Spark.View.new( template, 'body' );
// The DOM body will now be:
// <body>
// <h1>Hello World!</h1>
// </body>
Any variables in the Jade template will be observed and when they change the DOM will be updated automatically for you.
var person = Spark.Object.new({ name : 'Fred' });
var template = 'h1 Hello #{person.name}!';
var view = Spark.View.new( template, 'body', { person : person } );
// The DOM body will now be:
// <body>
// <h1>Hello Fred!</h1>
// </body>
person( 'name', 'Natalie' );
// The DOM body will now be:
// <body>
// <h1>Hello Natalie!</h1>
// </body>
Spark attaches special meaning to template variables using flags after the variable name. For
example, to attach the !ignore
flag to the variable #{person.age}
simply put it after the
variable's name like this #{person.age!ignore}
. The flags that Spark supports are:
- !bind
- !ignore
- !remove
This flag should be used in a tag's attribute list after the name of an event. This will cause the
Spark.View
to bind to the named event. If you would like to specify a callback function just put
its path in the locals Object
after the flag. For example, the following would bind the click
event on the span to the property nameClicked
in the local variable person
.
h1 span( #{click!bind.person.nameClicked} ) #{person.name}
This flag will prevent the Spark.View
object observing the property specified in the variable. If
the property changes after the Spark.View
builds the template, the DOM will not be updated.
var person = Spark.Object.new({ name : 'Fred' });
var template = 'h1 Hello #{person.name!ignore}!';
var view = Spark.View.new( template, 'body', { person : person } );
// The DOM body will now be:
// <body>
// <h1>Hello Fred!</h1>
// </body>
person( 'name', 'Natalie' );
// The DOM body will still be:
// <body>
// <h1>Hello Fred!</h1>
// </body>
This flag will cause the whole variable to be removed from the template. The following two templates are the same as far as Jade is concerned:
h1 Hello, #{person.name!remove}!
h1 Hello, !
You can nest Spark.View
s within each other by simply passing the sub-view to the parent view as
local variables and then reading the sub-view's html
property in the template. Any changes that
happen on the sub-view will propagate upwards and the parent view will update. For example, the
following code nests the personView
Spark.View
within the mainView
Spark.View
.
var person = Spark.Object.new({ name : 'Fred', age : 42 });
var personTemplate = 'h1 Hi, my name is #{person.name}. I am #{person.age} years old.';
var personView = Spark.View.new( personTemplate, person );
var mainTemplate = 'div !{personView.html}';
var mainView = Spark.View.new( mainTemplate, 'body', { personView : personView } );
// The DOM body will now be:
// <body>
// <div>
// <h1>Hello, my name is Fred. I am 42 years old.</h1>
// </div>
// </body>
person.increment( 'age' );
// The DOM body will now be:
// <body>
// <div>
// <h1>Hello, my name is Fred. I am 43 years old.</h1>
// </div>
// </body>
Note that the jQuery selector parameter is left off for the sub-view. This is because it does not need to insert itself into the DOM, it will be inserted by the parent template.
For more documentation please visit the wiki.