Starting Out

Introduction

OJ simplifies creation and manipulation of the DOM by abstracting the web into objects. It literally stands for Object Javascript, and was created under the philosophy that object encapsulation simplifies development.

To this end OJ provides several Collection Types and Form Types to help you create your website server side and manipulate it dynamically client-side. Two-way model binding is built right in if you use Backbone models (or anything with .on .off event binding). Collection binding is built into oj.List and oj.Table, for more complex views.

For simple tag creation OJ provides a series of tag functions, one for every tag (<div>, <span>, <ul>, <table>, <a>, etc), to build up structure of your site and help create the collection and form types you are using. These tag functions allow you to create html structure, css, and bind jquery events simultaneously.

To truly master OJ it is encouraged to create your own custom types; List and Table are going to get you quite far, but it is much easier to think in terms of ChatWindow or FriendList than to manually manipulate several things at once by hand. To this end OJ provides a createType function and some inheritable base types to help you create types of your own. With these base types, model binding is quite easy.

For server side use of oj a command-line tool called oj can be installed with node's package manager npm. This tools purpose is to compile oj file types into html files. It supports --watch options to help recompile when things change. It also supports minification of html, javascript, and css for production with --minify. Important Note: This tool is not a web server. It is a static site generator (think for github pages), but for more complex scenarios an express plugin is in the works.

As always contributions are most welcome. Feel free to send pull requests or to report bugs and feature requests as issues.

License

Copyright (c) 2013 Evan Moran
OJ may be freely distributed under the MIT license

Creating Tags

oj.tag

The core function that implements the individual tag functions.

tag(tagName, attributes..., children...)

tagName is the string name of a tag such as "div"

attributes are any object that maps attribute name to value. These can be in any order after tagName. In addition attributes are smart in a couple ways:

  1. Attributes named after jQuery mouse or keyboard events will be bound with jQuery

  2. Style attributes can be defined with an object instead of a string

  3. Style attribute object keys can be written in camelCase and will translated to dashed-case for you

  4. class may be abbreviated as c. This is the only abbreviation in OJ, but the class keyword makes it helpful.

Example: Create a div with oj.tag

CS
JS

Tag Functions

Since tags are a core part of OJ an oj.<tagName> function has been created for every tag in HTML. This includes <div>, <input>, <button>, etc.

These functions support all the fanciness of oj.tag including event binding, and style objects/camelCase.

Example: Using some tag functions

CS
JS

Example: Nesting tags

CS
JS

Example: Creating tags with loops

CS
JS

Creating CSS

oj.css

The function that defines all css within OJ. This function ties data like a tag function but during the compile step converts the data to CSS. Supports nested selectors, camelCase rules, nested @media queries.

This method can be called multiple times in any context a tag function could be called. Rules will be unioned together. If exactly the same rule is made the last called will be used.

css(rulesObject)

Example: Create CSS class selectors

CS
JS

Form Types

These objects create smart form elements that two-way bind to parts of a model: a model-key. Why only part of a model? The reason is controls usually only affect a single key, for example the email field, or name field might be bound to a TextBox. While a CheckBox might bind to boolean properties wantsTheNewsletter or isRegistered. These keys can all be on the same UserModel, but they affect different things.

Example of binding a TextBox

Create a user

  var UserModel = new Backbone.Model.extend();
  var user = new UserModel({name:'Evan'});

Bind TextBox to the user's name

  var TextBox({model: user, key:'name'});

Two way binding will happen automatically. If you change the model's name the TextBox will update. If you type in the TextBox the model will update.

The model-key binding syntax works on all Form Types the inherit from ModelKeyView.

oj.Button

A built-in OJ type that creates and manipulates a button element. The label property can set the button text.

Button(label, properties)

base:
properties:
label

The text of the button (read-write).

methods:
click(fn)

A pass through method to jQuery click event.

Like the jQuery function, calling with a fn will bind that function to the click event. Calling without an argument will cause the button click event to be triggered.

Example: Detect click event

CS
JS

oj.CheckBox

An OJ object that creates and manipulates a CheckBox control. The value property can be set in the first argument, or through via properties.

CheckBox(value, properties)

base:
properties:
value

The value of the control as a boolean (read-write).

True means checked. False unchecked.

model

Bind a model to this control (read-write, inherited).

key

Bind a specific key of a model to this control (read-write, inherited).

Example: Detect CheckBox change event

CS
JS

oj.ListBox

A built-in OJ type that creates and manipulates a ListBox form element. Binding to models is supported through ModelKeyView, The value is a string that changes the list box's text. The property options must be specified so the list box knows which options to drop down.

ListBox(value, properties)

base:
properties:
value

The value of the control as a string (read-write).

options

Array of options that the list box should be allowed to take on.

model

Bind a model to this control (read-write, inherited).

key

Bind a specific key of a model to this control (read-write, inherited).

Example: Detecting changes in a ListBox

CS
JS

Example: Changing ListBox options dynamically

CS
JS

oj.Text

A built-in OJ type that creates and manipulates a tag such as a <div> or <span>. Generally this is done with tag functions but occasionally you will want to bind text to model data, or change it dynamically.

The value is a string that changes the text's value.

Text(value, properties)

base:
properties:
value

The value of the tag as a string (read-write).

model

Bind a model to this control (read-write, inherited).

key

Bind a specific key of a model to this control (read-write, inherited).

Example: Changing Text automatically

CS
JS

oj.TextBox

A built-in OJ type that creates and manipulates a TextBox form element. value is a string that changes the text box's text. This type supports binding to models through ModelKeyView.

TextBox(value, properties)

base:
properties:
value

The value of the control as a string (read-write).

model

Bind a model to this control (read-write, inherited).

key

Bind a specific key of a model to this control (read-write, inherited).

live

Change events should update "live" on keypress instead of waiting for blur event (default=true)

Example: Detecting TextBox change event

CS
JS

oj.TextArea

A built-in OJ type that creates and manipulates a TextArea form element. Binding to models is supported through ModelKeyView, The value is a string that changes the text box's text. For convenence arguments are joined with newline to allow simple multi-line input in JavaScript.

TextArea(valueLine1, valueLine2,..., properties)

base:
properties:
value

The value of the control as a string (read-write).

model

Bind a model to this control (read-write, inherited).

key

Bind a specific key of a model to this control (read-write, inherited).

live

Boolean value indicating if change events should update "live" on keypress instead of waiting for blur event (default=true)

Example: TextArea Multi-line arguments

CS
JS

Example: Detecting TextArea change event

CS
JS

Model Binding

All form controls support model binding through ModelKeyView.

Example: Two-way model binding on a user `name` attribute

CS
JS

Example: Two-way model binding on a user `name` and `strength` attributes

CS
JS

Collection Types

These objects are built-in to OJ and designed to be the building blocks for more complex websites. BulletList, NumberList exist to easily create numbered lists or bulleted lists.

All collection types can be created directly through a list of arguments, or by binding to a Backbone.Collection object. If a collection object is used these objects will minimally rebuild themselves as the collection changes.

List exists to create lists of items without symbols. It uses <div> for its tags instead of <ul> or <li> as this is often desired for ChatWindows or FriendLists -- basically this is ideal for whenever you don't really want numbers or bullets.

Table is the most complex object built into OJ. It supports everything List does, but adds another dimension. It also supports Backbone.Collection binding and is designed to support hundreds of thousands of rows. In generally OJ is built around the idea of direct DOM manipulation. Server-side it builds strings, but client side it just modifies elements directly for much improved performance.

All collection objects inherit from CollectionView and View and so definitely take a look at what those provide.

oj.BulletList

This is a simple alias for oj.List to abstract creating bulleted lists. It overrides the properties tagName to ul, and itemTagName to li.

CS
JS

oj.NumberList

This is a simple alias for oj.List to abstract creating numbered lists. It overrides the properties tagName to ul, and itemTagName to li.

CS
JS

oj.List

Lists are at the heart of OJ. They are a fundamental building block that lets you bind collections of models to views. That can be as simple as NumberList and BulletList above. Or they can be more complex and render Chat Messages, Todo Lists, or whatever else you want tied to data.

Lists can be constructed by basic types:

CS
JS

Lists can be constructed from oj objects:

CS
JS

List(items..., properties)

arguments:
items...

Any number of values to add to the list.

Constructing with these arguments has the same effect as setting the items property.

properties

An object to bulk set properties.

Keys that aren't properties are passed as attributes to the root element.

base:
properties:
count

Number of items (Number, read-only))

collection

Inherited from CollectionView.collection

The collection for the view. This can be an Array or a Backbone.Collection

When Backbone is used changes to the collection will cause the view to be automatically redrawn. This is done minimally so adds and removes cause fewest redraws possible.

each(model)

Inherited from CollectionView.each

A mapping function that turns a model into a view.

Use this whenever you set models to specify which part of the model to render.

tagName

Name of tag (String, write-construct)

itemTagName

Name of tag for each item (String, read-write)

$items

Helper to get all item jquery elements ([jQueryElement], read-only))

methods:
item(index, oj)

Get or set the item at index index may be negative to access elements at the end.

When view is specified the item is set to the oj view When view is omitted the item value is returned How this value is returned is handled by ojValue a included jQuery plugin.

list.item(2)              // get item
list.item(2, 'hello')     // set item to 'hello'
list.item(2, function(){  // Set item to a TextBox
  TextBox 'goodbye'
}
$item(index)

Helper to get an item's containing element wrapped by jquery

add(index, oj)

Add item at index

index may be negative to access elements at the end.

oj may be any oj view or object.

list = List('a','b');      // ['a','b']
list.add(1, 'c');          // ['a','c','b']
list.add(-1, 'd');         // ['a','c','b','d']
remove(index)

Remove item at index index may be negative to access elements at the end.

list = List('a','b','c');  // ['a','b','c']
list.remove(1);            // ['a','c']
list.remove(-1);           // ['a']
push(oj)

Add a new last item

list = List('a','b');      // ['a','b']
list.push('c');            // ['a','b','c']
pop()

Remove the last item

list = List('a','b');      // ['a','b']
list.pop();                // ['a']
shift(oj)

Remove the first item

list = List('a','b');      // ['a','b']
list.shift();              // ['b']
unshift(oj)

Add a new first item

list = List('a','b');      // ['a','b']
list.unshift('c');         // ['c','a','b']
clear(oj)

Remove all items

list = List('a','b');      // ['a','b']
list.clear();              // []
move(ix, ix2)

Move item from index ix to index ix2

list = List('a','b','c'); // ['a','b','c'] list.move(2,0); // ['c','b','a']

swap(ix, ix2)

Swap items at index ix to index ix2

list = List('a','b','c'); // ['a','b','c'] list.swap(1,2); // ['a','c','b']

oj.Table

Tables are another building block in OJ. Like [List] it can be used to show static data or be bound to collections of models. When the collection changes it will automatically add and remove rows to rerender the table.

Tables can be constructed with arrays of values:

Table(
  [1,2,3],
  [4,5,6]
);

Table(rows..., properties)

arguments:
rows...

Any number of rows to add to the table.

Constructing with these arguments has the same effect as setting the items property.

properties

A object to bulk set properties.

Keys that aren't properties are passed as attributes to the root element.

base:
properties:
rowCount

Number of rows (Number, read-only))

columnCount

Number of columns (Number, read-only))

collection

Inherited from CollectionView.collection

The collection for the view. This can be an Array or a Backbone.Collection

When Backbone is used changes to the collection will cause the view to be automatically redrawn. This is done minimally so adds and removes cause fewest redraws possible.

each(model,cell)

Inherited from CollectionView.each

A mapping function that turns a model into a view.

Use this whenever you set models to specify which part of the model to render.

$trs

Accessor to all row <tr> elements (read-only)

$ths

Accessor to all <th> elements (read-only)

$table

Accessor to <table> element (read-only)

$thead

Accessor to <thead> element (read-only)

$tbody

Accessor to <tbody> element (read-only)

$tfoot

Accessor to <tfoot> element (read-only)

$caption

Accessor to <caption> element (read-only)

$colgroup

Accessor to <colgroup> element (read-only)

$theadTR

Accessor to <tr> element in <thead> (read-only)

$tfootTR

Accessor to <tr> element in <tfoot> (read-only)

methods:
row(rx, ojArray)

Get or set the row at row index rx rx may be negative to access elements at the end.

When ojArray is specified the row cells are set to the specified oj views.

When ojArray is omitted the row values are returned.

How this value is returned is handled by ojValue jQuery plugin.

cell(rx, cx, oj)

Get or set the cell at row index rx, column index cx

rx and cx may be negative to access elements at the end.

When oj is specified the cell is set to the value of the oj view.

When oj is omitted the cell value is returned.

How this value is returned is handled by ojValue jQuery plugin.

clear()

Remove everything in the table: rows, headers, footers, and captions.

clearBody()

Remove all rows in body

clearHeader()

Remove the header

clearFooter()

Remove the footer

addRow(rx, ojArr)

Add row at index rx

rx may be negative to access elements at the end.

ojArr is an array of any oj views or objects.

removeRow(rx)

Remove item at index rx

pushRow(ojArr)

Add a new last row

ojArr is an array of oj views or objects.

popRow()

Remove the last row

shiftRow()

Remove the first row and return it.

unshiftRow(ojArr)

Add a new first row ojArr is an array of oj views or objects.

moveRow(rx, rx2)

Move row from index rx to rx2

swapRow(rx, rx2)

Swap row at index rx to rx2

$tr(rx)

Accessor to <tr> at row index rx

$td(rx,cx)

Accessor to <td> at row index rx, column index cx

Creating Types

The point of OJ is creating types that better abstract the web. To do this OJ includes a function called oj.createType.

Features

  • Creates 100% real javascript types
  • Works seemlessly between javascript and coffee-script
  • First class properties support:
    • Properties by value
    • Properties by get and set functions
  • Supports Constructors and Methods
  • Supports Inheritance
    • inherits up to one Type
    • Call super with this.super.methodName()
  • new is optional

oj.createType

This function creates new type constructors. is a big part of why OJ types are so easy to create and use. Generally you should create new types when the component is well understood and often when it has an analogous model.

createType(name, options)

arguments:
name

The string name of the type you want to create.

options

An object that specifies properties, methods, constructor, and an inheritance base type.

See more information below:

options:
base:

The type to inherit. When making OJ views use a base type.

properties:

Define the type's properties.

methods:

Define the type's methods.

To call super use: `TypeName.base.methodName.apply(this, arguments);

constructor:

Optionally define a constructor. this will be bound correctly.

To call super use: `TypeName.base.constructor.apply(this, arguments);

Example

// Create a User type
var User = oj.createType('User', {

  constructor: function(props){
    // Built in method to set all
    // properties by name
    this.set(props);
  },

  // Create properties
  properties: {
    name: null,
    birthDate: null,

    // The age property is calculated
    // automatically from birthDate
    age: {
      get: function(){
        var today = new Date();

        var age = today.getFullYear() -
          this.birthDate.getFullYear();

        var month = today.getMonth() -
          this.birthDate.getMonth();

        var birthDateIsAfterToday = (
          month == 0 && (
            today.getDate() <
             this.birthDate.getDate()
          )
        );
        if (birthDateIsAfterToday)
          age--;
        return age;
      }
    }
  },

  // Create methods
  methods: {
    isEighteen: function(){
      return this.age >= 18;
    }
  }
});

// Create the user named Batman
var user = new User({
  name:'Batman',
  birthDate:new Date(1974,2,1)
});

// Show that the age property works
div(user.name + ' is ' +
  user.age + ' years old.');

div(user.name + ' is eighteen: ',
  function(){
    strong(user.isEighteen())
  }
);

Type Interface

All types created by oj.createType have the following methods and properties.

properties:
type

The type that made this instance (read-only)

typeName

The name of type that made this instance (read-only)

properties

Array of all properties the type supports (read-only)

methods

Array of all methods the type supports (read-only)

methods:
get()

Get all properties as an object

get(prop)

Get the value of property prop. undefined is returned if prop is not a valid property

set(prop,val)

Set property prop to value val

set(props)

Set all properties at once. props is an object mapping key to value. Invalid keys defined in props are ignored.

has(prop)

Determine if string prop is a property of this instance

can(method)

Determine if string method is a method of this instance

toJSON()

Convert properties to json

Base Types

For those of you who want to make your own rich oj views, there are a few inheritable types that will make your life easier.

View - The heart of OJ, this makes objects behave like tag functions.

ModelKeyView - Binds the view to a part of a model (a model + key). Used by all the form elements. Great for creating two-way bindings.

CollectionView - Bind the view to a collection of models. Used by List and Table. Automatically binds to collection add, remove, change events.

oj.View

This object is the basis of much of the functionality of OJ. It emits creation events so that objects act like oj.tag. It creates the root element of your object and gives convenient access to it through el. It provides an attributes property and related methods to let you set and get attributes.

All types created using oj.createType behave this way.

var textbox = TextBox({value:'my text'});

Is the same as:

var textbox = TextBox();
textbox.value = 'my text';

(Note: because oj.createType removes the need to use new, so in the above example it wasn't necessary to call new TextBox(). See oj.createType if you want to learn more about why this was done.)

Any options that don't map to properties will be passed through to the root element as attributes. This lets this work as you would expect:

TextBox({value:'Placeholder text', id:'id123', style:{color:'red'}})

Also options can come in any order. This is especially useful for defining style ()

TextBox({id:'id123'}, 'my text', {style:{
    color:'red'
  }
})
properties:
el

The root element (read-only, cached).

$el

The jquery-enabled root element (read-only, cached)

attributes

Get all attributes for the root element (read-only)

methods:
addAttribute(name,value)

Add an attribute. Supports everything oj.tag supports, including jQuery events and style renaming such as fontSize to font-size.

addAttribute(name,value)

Add an attribute. Supports everything oj.tag supports, including jQuery events and style renaming such as fontSize to font-size.

addAttributes(obj)

Add multiple attributes at once. Supports everything oj.tag supports. Including jQuery events and style renaming such as fontSize to font-size.

removeAttribute(name)

Remove attribute with by name.

removeAttributes(list)

Remove all attributes in the list.

$(selector)

Find elements from root with jQuery.

toHTML()

Convert view to html

toDOM()

Convert view to dom

toString()

Convert view to a string. By default this calls toHTML()

oj.ModelKeyView

base:
properties:
model

The model part of the model-key that partially binds a model. Both key and model are required.

key

The key part of the model-key that partially binds a model. Both key and model are required.

events:
modelChanged(...)

Overridable event method called when the model is changed

When overriding be sure to call the base method

viewChanged(...)

Call this event method to when the view changes. This will cause the model to be updated automatically.

oj.CollectionView

base:
properties:
collection

The inherited collection property for the view. This can be an Array or a Backbone.Collection.

When Backbone is used changes the CollectionView automatically binds to changes in the collection and calls the following methods:

  • collectionModelAdded
  • collectionModelRemoved
  • collectionModelChanged
  • collectionModelDestroyed
  • collectionReset

When implementing a oj.CollectionView these event methods should be overriden to correctly update state as the collection changes.

models

Alias for collection property.

events:
collectionModelAdded(...)

Overridable event method called when a model is added to the collection

collectionModelRemoved(...)

Overridable event method called when a model is removed from the collection

collectionModelChanged(...)

Overridable event method called when a model changes

collectionModelDestroyed(...)

Overridable event method called when a model is destroyed

collectionReset()

Overridable event method called when the entire collection is remade

Commandline Tool

OJ has the capability of building static websites on the command-line using the oj command. This is best for sites that don't change content upon request -- think Github Pages. This does not mean the site cannot have ajax requests and dynamic content, just that the tool isn't for building that.

Features

  • Unified Templating: .oj and .ojc generate js, html, and css
  • Built in coffee-script support: .oj means javascript, .ojc means coffee-script.
  • Minification: All js, css, html will be minified when --minify is set
  • Files and Directories can be built, recursed upon, and watched
  • Files can be included from other files using node's require syntax.
  • Node modules can be included as well. Simply require them, and they will also be brought into the system (similar to browserify).
  • Built in support for coffee-script with .ojc files. You don't even need to install coffee-script, it just works.

Install

To use OJ on the server you will need to install the oj command built on top of node.js. For this you need to install node. There are many ways to do this installation, but this will get you started:

Install Node

Install node on OSX with homebrew:

brew install node

Install node on Ubuntu with apt-get:

sudo apt-get install nodejs npm

Install OJ Command

Finally install oj with npm:

npm install -g oj

File Types (.oj / .ojc)

The oj.js javascript library works perfectly fine inside of .js, or .coffee files. The only issue is that it gets tiring writing oj in front of everything: oj.html, oj.Table, etc.

To solve this OJ supports two file types:

  • .oj is javascript
  • .ojc is coffee-script

These files have been fully integrated into node. This means you can include other files using require, and you must use module.exports to set the what the module should return. Here are some examples:

.oj example (javascript):

# hello.oj
module.exports = return [html,
  [head],
  [body,
    [div 'Hello world']
  ]
]

.ojc example (coffee-script):

# hello.ojc
module.exports = ->
  html ->
    head ->
    body ->
      div 'Hello world'

Usage

The oj command builds .oj and .ojc file types into .html files.

oj [options] <file> <dir> ...

Options:

  -h, --help             output usage information
  -V, --version          output the version number
  -m, --minify           Turn on minification (default: false)
  -o, --output <dir>     Directory to output all files to (default: .)
  -r, --recurse          Recurse into directories (default: off)
  -v, --verbose <level>  Turn on verbose level 0-3 (default: 1)
  -w, --watch            Turn on watch mode (default: off)

When options are omitted these are the defaults:

--output defaults to ./
--minify defaults to off<br>
--verbose defaults to 1

Ignored file prefixes

  • Partials and Templates (start with _)
  • OJ Plugins (start with oj.)
  • Hidden files (start with .)

Examples

Build hello.oj to current directory

oj hello.oj

Build hello.oj without minification to www directory

oj -d -o www hello.oj

Watch hello.oj and build to www directory

oj --watch -o www hello.oj

Build pages directory to www

oj -o www pages

Recursively build pages directory to www

oj -r -o www pages

Recursively watch and build pages directory to www

oj -w -r -o www pages