About
JavaScript is an extremely powerful and expressive scripting language that is used extensively by websites and web applications. Additionally the V8 JavaScript engine would serve as a fantastic script engine for video games and offline applications.
Object-oriented programming (OOP) is nothing new to JavaScript developers. JavaScript offers prototype based classes which can be instantiated and have member fields, methods and a constructor. Each instance member must be assigned using the prototype object. Whilst this does mean a little more typing, it does provide an excellent solution...until class inheritance (aka extends) comes into play.
For small scripts this doesn't really pose much of an issue. This does become a problem for those who prefer to use classical OOP design patterns when developing complex applications.
What is Capri?
The fundamental purpose of Capri is to provide the ability to define and extend classes and namespaces in a way that is clean and easy to understand. The secondary purpose of Capri is to provide a reusable toolset that caters to common needs.
Capri is modular so that developers can decide whether to use one of the standard distributions, or to create a custom combination of modules (available individually from repository).
With Capri
// define class
$class('my.Greeting', {
__construct: function(name) {
this.name = name;
},
message: function() {
return 'Hey, ' + this.name + '!';
}
});
// using class
var greet = new my.Greeting('Slartibartfast');
alert(greet.message());
Without Capri
// define namespace if not already defined
if (my === undefined)
my = {};
// define class
my.Greeting = function(name) {
this.name = name;
};
my.Greeting.prototype.message = function() {
return 'Hey, ' + this.name + '!';
};
// using class
var greet = new my.Greeting('Slartibartfast');
alert(greet.message());
Refer to tutorial pages for more detailed explanations of classes.
Adding custom functionality to namespaces can be cumbersome especially with nesting. The Capri $namespace function provides access to a namespace regardless of whether the namespace has been defined. The function also makes it easy to add to an existing (or new) namespace:
With Capri
// add function to deep namespace
$namespace('my.app.util', {
sonic: function() {
return 'Fish fingers and custard';
}
});
// usage
var msg = my.app.util.sonic();
Without Capri
// define namespaces if not already defined
if (my === undefined)
my = {};
if (my.app === undefined)
my.app = {};
if (my.app.util === undefined)
my.app.util = {};
// add function to deep namespace
my.app.util.sonic = function() {
return 'Fish fingers and custard';
};
// usage
var msg = my.app.util.sonic();
What is jQuery?
jQuery is an excellent framework that make it extremely easy (and fun) to manipulate DOM elements. In a nutshell it allows developers to select elements using CSS3 compliant selectors. The returned set of elements can then be manipulated in various ways to add interactivity (and a little flare!)
Some Capri modules require the jQuery library in order to function. For convenience two variants of Capri are provided; one that doesn't depend upon jQuery (standalone), and another that does (jQuery plugin).
How does the Capri jQuery plugin extend jQuery?
Capri provides an alternative widget architecture that is object-oriented, supports namespaces and integrates into jQuery as a plugin called widget.
A large web application can be spread across multiple scripts:
- Easier to maintain.
- Allows team members to work on their designated scripts.
- Avoids large script dependancy when website is first loaded because scripts can be loaded on demand.
Scripts and styles can be included dynamically. There are a variety of ways in which this can be achieved, but not all work across all major web browsers. Capri aims to simplify this task. It is even easier if the base address of the application is specified:
// define base address of application
capri.DocumentManager.setBaseUri('http://example.com/app');
// include a stylesheet and several scripts upon startup
$include('~/css/editor.css');
$include('~/js/editor.js');
$include('~/js/converter.js', function() {
// this callback is invoked once prior includes have been included
example.converter.init();
});
// initialise page once both page and includes have been loaded
$startup(function() {
$('#my-button').click(function() {
// dynamically load script when button is clicked
$include('~/js/profile.js', function() {
// callback once included!
});
// include all queued scripts and styles
$include.process();
});
});

