/* The following examples explain the common design pattern for OxJS UI widgets: an inheritance model that is neither classical nor prototypal, but "parasitical" (a term coined by Douglas Crockford). In a nutshell, "instances" are created by augmenting other instances, but in addition to private members (`var foo`) and public members (`that.bar`), they can have shared private members (`self.baz`). `self` cannot be accessed from outside, but since `self` itself is an argument of the "constructor", an instance can inherit its parent's `self` by passing its own `self`. */ 'use strict'; /* Load the UI module. */ Ox.load(['Image', 'UI'], function() { /* Create our own namespace. */ Ox.My = {}; /* First, lets build the most basic Box widget. A widget is a "constructor" function that takes two (optional) arguments, `options` and `self`, and returns a widget object. It's not a constructor in JavaScript terms though: It doesn't have to be called with `new`, and doesn't return an `instanceof` anything. It just enhances another widget object and returns it. */ Ox.My.Box = function(options, self) { /* This is how every widget "constructor" begins. `self` is the widget's shared private object. */ self = self || {}; /* `that` is the widget itself, its public object, or, in JavaScript terms, its `this`. Every widget "inherits" from another widget by simple assignment. All public properties of the "super" widget, i.e. all properties of its `that`, will be present on our own `that`. In this case, we use Ox.Element, the "root" widget at the end of the inheritance chain, and pass an empty options object. But we always pass our own `self`, which means that any property that Ox.Element (or any other widget in the inheritance chain) adds to `self` will be present on our own `self`. Then we call the public `defaults`, `options` and `update` methods of Ox.Element. `defaults` assigns the defaults object to `self.defaults` and copies it to `self.options`, `options` extends `self.options` with the options object, and `update` adds one or more callbacks that are invoked whenever, by way of calling the `options` method, a property of `self.options` is modified or added. */ var that = Ox.Element({}, self) .defaults({ color: [128, 128, 128], size: [128, 128] }) .options(options || {}) .update({ color: setColor, size: setSize }) .addClass('OxMyBox'); /* The second part of the "constructor" function can be thought of as the "initializer", and contains everything needed to set up the "instance". In this case, we just define a minimum and maximum size and then set the widget's color and size. We could have used `var minSize` and `var maxSize` here, but by using `self` for private variables that we want to be accessible across all the widget's methods, we can be sure that inside such methods, any local `var` is actually local to the method. */ self.minSize = 1; self.maxSize = 256; setColor(); setSize(); /* Third, we declare the widget's private methods. These are just function declarations, hoisted to the top of the "constructor". */ function setColor() { /* To interact with the DOM, Ox.Element (and any widget derived from it) wraps jQuery. If you type Ox.Element() in the console, you will get something like `[
]`, and the widget's prototype has all the methods of a `$('
Ox.My.RoundedBox({
color: [255, 0, 0],
radius: 32
})
.appendTo(Ox.$body)
.options({size: 256})
.showOptions();
*/
/*
Its also possible to pass objects or other elements as options
*/
Ox.My.MetaBox = function(options, self) {
self = self || {};
var that = Ox.My.Box({}, self);
that.defaults(Ox.extend(that.defaults(), {
boxes: []
}))
.options(options || {});
self.options.boxes.forEach(function(box) {
that.append(box);
});
return that;
};
/*
Now its time to create some boxes for this demo:
*/
window.boxes = Ox.My.MetaBox({
boxes: [
Ox.My.Box({
color: [64, 128, 255]
}),
Ox.My.RoundedBox({
color: [255, 128, 64]
})
],
size: 384
})
.appendTo(Ox.$body);
});