<%= template.import("header.html", {}, "header") %>
<%= template.import("lateralbar.html", {}, "lateralbar") %>

HappyRhino gives structure to client-side web applications by bringing a complete build system with a a rich API similar to Backbone.js.

hr.js is an open-source component of FriendCode.

Current version is <%- hr.configs.version %>, code is disponible on GitHub : FriendCode/hr.js.

Checkout a list of web-applications which are using hr.js :

  • FriendCode, Realtime collaborative code editor built for the cloud era.
  • Doks.io, Searching documentation made easy.
  • TV.js, Apple TV for Torrent Streaming in JS (Node/Chrome).
  • Reportr, Your life's personal dashboard.
  • GitRap, Distributed Git based Forums.

<%= view.component("counter", { prefix: "Documentation updated ", suffix: " ago.", from: new Date(hr.configs.revision) }) %>

">Installation

Simply install hr.js using NPM :

npm install -g hr.js

or

npm install -g git+https://github.com/FriendCode/hr.js.git#master

">Get started

HappyRhino lets you create a simple base application using :

hr.js new -d my_app

Build and run your application using:

hr.js all -d my_app

And here is your first client-side application with HappyRhino!

">Build system

">Defining an application

An application in hr.js need a base build configuration, this configuration is stored in a "build.js" file:

<%= view.component("code", {code: "build/build.js"}) %>

Here is a list of all the differents options for build process :

<%= view.component("code", {code: "build/options.js"}) %>

">Build & Run your application

For building, simply run in a command line tool : hr.js all.

You can also only build with : hr.js build.

Or only run the simple static server with : hr.js run.

">Modularity

HappyRhino uses require.js as module loader.

<%= view.component("code", {code: "build/module.js"}) %>

">Arguments and revisions

Each build use a unique revision timestamp, this revision id is useful for avoiding cache during resources requests.

<%= view.component("code", {code: "build/revision.js", run: true}) %>

The build process can pass arguments to the client side application :

<%= view.component("code", {code: "build/options_args.js"}) %>

And arguments are simply accessible in the client side :

<%= view.component("code", {code: "build/args.js"}) %>

">Application

The module Application represent the base for your application, it uses to describe the main entry point of your application and its configurations.

The class Application inherit from ">hr.View.

">extend hr.Application.extend(properties, [classProperties])

To create an Application class of your own, ">extend hr.Application, providing instance properties, as well as optional classProperties to be attached directly to the application's constructor function.

<%= view.component("code", {code: "application/extend.js"}) %>

">run application.run()

After extending the hr.Application class, you need to start your new application.

<%= view.component("code", {code: "application/run.js"}) %>

">title application.title([newValue, absolute])

Get or set the page title, title could be relative to the application (format: @appname - @title) or absolute (format: @title). This method use ">head.

<%= view.component("code", {code: "application/title.js"}) %>

">head application.head

Property head of application let you easily manage page informations such as title, metas, links, crawling.

<%= view.component("code", {code: "application/head.js"}) %>

">View

">extend hr.View.extend(properties, [classProperties])

The first thing who have to do for creating a new view is extending the basic view class.

<%= view.component("code", {code: "view/extend.js"}) %>

">template

Views in hr.js can easily uses templates by defining property template with the template name and uses templateContext to return the variables for the template.

For using templates, you need to specify the ressource loader for templates : ">Templating/Loading.

<%= view.component("code", {code: "view/template.js"}) %>

template name could alse be given by a function, for example :

<%= view.component("code", {code: "view/template_function.js"}) %>

">render view.render()

Render the view is easy using the method render, you can bind the events "render" (after rendering) or "ready" (first time rendering).

<%= view.component("code", {code: "view/render.js"}) %>

By default, view use template for rendering, but you can redefine render :

<%= view.component("code", {code: "view/render_extend.js"}) %>

">events

Events are written in the format {"event selector": "callback"}. The callback may be either the name of a method on the view, or a direct function body. Omitting the selector causes the event to be bound to the view's root element (this.el). By default, delegateEvents is called within the View's constructor for you, so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself.

The events property may also be defined as a function that returns an events hash, to make it easier to programmatically define your events, as well as inherit them from parent views.

Using delegated events provides a number of advantages over manually using jQuery to bind events to child elements during render. All attached callbacks are bound to the view before being handed off to jQuery, so when the callbacks are invoked, this continues to refer to the view object. When delegateEvents is run, perhaps with a different events hash, all callbacks are removed and delegated afresh — useful for views which need to behave differently when in different modes.

<%= view.component("code", {code: "view/events.js"}) %>

">components

Views in hr can easily manage sub-views using components, these components can be added directly in the templates : ">Learn more about it

Defining a view as a component for temlate is really easy :

<%= view.component("code", {code: "view/component.js"}) %>

">Templating

">Syntax

hr.js allow view to manage in a simple way templates.

Template can interpolate variables, using <%= … %>, as well as execute arbitrary JavaScript code, with <% … %>. If you wish to interpolate a value, and have it be HTML-escaped, use <%- … %>.

<%= view.component("code", {code: "template/syntax.html"}) %>

">Components

Components in template is a great way to manage child views.

Template components have to been registrated using ">hr.View.Template.registerComponent

<%= view.component("code", {code: "template/components.html"}) %>

You can after that easily access to components views in your view :

<%= view.component("code", {code: "template/components.js"}) %>

">Loading

For using templates, you need to specify to hr how to load a template by name. Templates use the resources namespace "templates" :

<%= view.component("code", {code: "template/load.js"}) %>

">Class

The module class is the base for all the modules in hr.js, giving the object the ability to bind and trigger custom named events. Events do not have to be declared before they are bound, and may take passed arguments.

">extend hr.Class.extend(properties, [classProperties])

To create a class of your own, you extend hr.Class and provide instance properties, as well as optional classProperties to be attached directly to the constructor function.

extend correctly sets up the prototype chain, so subclasses created with extend can be further extended and subclassed as far as you like.

<%= view.component("code", {code: "class/extend.js"}) %>

">initialize new hr.Class([options])

initialize represents the constructor of the class, object passed to initialize is merged with ">defaults into options.

<%= view.component("code", {code: "class/initialize.js", run: true}) %>

">defaults hr.Class.defaults

defaults let you define the defaults properties of the objects. Properties of the objects are stored into options.

<%= view.component("code", {code: "class/defaults.js", run: true}) %>

">on object.on(event, callback, [context])

Bind a callback function to an object. The callback will be invoked whenever the event is fired. If you have a large number of different events on a page, the convention is to use colons to namespace them: "poll:start", or "change:selection". The event string may also be a space-delimited list of several events...

<%= view.component("code", {code: "class/on.js"}) %>

To supply a context value for this when the callback is invoked, pass the optional third argument: object.on('change', this.render, this)

Callbacks bound to the special "all" event will be triggered when any event occurs, and are passed the name of the event as the first argument. For example, to proxy all events from one object to another:

<%= view.component("code", {code: "class/on_all.js"}) %>

All event methods also support an event map syntax, as an alternative to positional arguments:

<%= view.component("code", {code: "class/on_map.js"}) %>

hr.js alse supports hierarchical events:

<%= view.component("code", {code: "class/on_sub.js", run: true}) %>

">off object.off([event], [callback], [context])

Remove a previously-bound callback function from an object. If no context is specified, all of the versions of the callback with different contexts will be removed. If no callback is specified, all callbacks for the event will be removed. If no event is specified, callbacks for all events will be removed.

<%= view.component("code", {code: "class/off.js"}) %>

">trigger object.trigger(event, [*args])

Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callbacks.

">triggerOnly object.triggerOnly(event, [*args])

Trigger callbacks for the given event, or space-delimited list of events. Subsequent arguments to trigger will be passed along to the event callbacks. But don't trigger parents events.

">once object.once(event, callback, [context])

Just like ">on, but causes the bound callback to only fire once before being removed. Handy for saying "the next time that X happens, do this".

">Model

The class Model let you define complex model in your applciation.

">extend hr.Model.extend(properties, [classProperties])

To create a Model class of your own, you extend hr.Model and provide instance properties, as well as optional classProperties to be attached directly to the constructor function.

<%= view.component("code", {code: "model/extend.js", run: true}) %>

">constructor / initialize new hr.Model([options], [attributes])

When creating an instance of a model, you can pass in the initial values of the attributes, which will be ">set on the model. If you define an initialize function, it will be invoked when the model is created.

">get model.get(attribute, [default])

Get the current value of an attribute from the model. For example: note.get("author.name")

">set model.set(attributes, [options])

Set a hash of attributes (one or many) on the model. If any of the attributes change the model's state, a "change" event will be triggered on the model. Change events for specific attributes are also triggered, and you can bind to those as well, for example: change:title, and change:content. You may also pass individual keys and values.

<%= view.component("code", {code: "model/set.js", run: true}) %>

">has model.has(attribute)

Returns true if the attribute is set to a non-null or non-undefined value.

">clear model.clear([options])

Clear the object attributes, options can contain silent to not triggering events change and clear.

">toJSON model.toJSON()

Return a copy of the model's ">attributes for JSON stringification. This can be used for persistence, serialization, or for augmentation before being sent to the server. The name of this method is a bit confusing, as it doesn't actually return a JSON string — but I'm afraid that it's the way that the JavaScript API for JSON.stringify works.

<%= view.component("code", {code: "model/tojson.js", run: true}) %>

">joints model.joints

Joints between models let you define complex models and relationship between models.

Property joints is a map of global key and model constructor function.

<%= view.component("code", {code: "model/extend.js", run: true}) %>

">Collection

Collections are ordered sets of ">models. You can bind "change" events to be notified when any model in the collection has been modified, listen for "add" and "remove" events, and use a full suite of Underscore.js methods.

Any event that is triggered on a model in a collection will also be triggered on the collection directly, for convenience. This allows you to listen for changes to specific attributes in any model in a collection, for example: documents.on("change:selected", ...)

">extend hr.Collection.extend(properties, [classProperties])

To create a Collection class of your own, extend hr.Collection, providing instance properties, as well as optional classProperties to be attached directly to the collection's constructor function.

">model collection.model

Override this property to specify the model class that the collection contains. If defined, you can pass raw attributes objects (and arrays) to ">add and ">reset, and the attributes will be converted into a model of the proper type.

<%= view.component("code", {code: "collection/model.js"}) %>

A collection can also contain polymorphic models by overriding this property with a function that returns a model.

<%= view.component("code", {code: "collection/model_polymorphic.js"}) %>

">toJSON collection.toJSON()

Return an array containing the attributes hash of each model in the collection. This can be used to serialize and persist the collection as a whole. The name of this method is a bit confusing, because it conforms to the JavaScript API for JSON.stringify works.

<%= view.component("code", {code: "collection/tojson.js", run: true}) %>

">Requests

The class Requests let you create simple or complex http requests in a easy way.

">Requests new hr.Requests(options)

The class Requests is very simple to use.

<%= view.component("code", {code: "requests/class.js", run: true}) %>

The Requests class get some usefull shortcuts class methods such as ">get or ">post

">get hr.Requests.get(url, arguments, options)

Easy way to do a get requests with some query arguments, it returns a ">Deferrer object.

<%= view.component("code", {code: "requests/get.js", run: true}) %>

">post hr.Requests.post(url, arguments, options)

Easy way to do a post requests with some body arguments, it returns a ">Deferrer object.

<%= view.component("code", {code: "requests/post.js", run: true}) %>

">getJSON hr.Requests.getJSON(url, arguments, options)

Like get but use JSONP callback to do cross-domain requests.

<%= view.component("code", {code: "requests/getjson.js", run: true}) %>

">Logger

The class Logger let you manage different log in a standart way with a global configuration.

">Logger.addNamespace hr.Logger.addNamespace(namespace, [handler])

Logger let you create logging object linked to a namespace and a handler.

The namespace is a string defining the context of messages to this logger.

The handler is an object with the following method : "log", "debug", "warn", "error"

<%= view.component("code", {code: "logger/namespace.js", run: true}) %>

">Logger.logging hr.Logger.logging

logging is a logger instance linked to the namespace "base".

Log messages are visible in the console of your navigator

<%= view.component("code", {code: "logger/logging.js", run: true}) %>

">Router

Web applications often provide linkable, bookmarkable, shareable URLs for important locations in the app. Until recently, hash fragments (#page) were used to provide these permalinks, but with the arrival of the History API, it's now possible to use standard URLs (/page). hr.Router provides methods for routing client-side pages, and connecting them to actions and events.

">extend hr.Router.extend(properties, [classProperties])

Get started by creating a custom router class. Define actions that are triggered when certain URL fragments are matched, and provide a routes hash that pairs routes to actions.

<%= view.component("code", {code: "router/extend.js"}) %>

">route router.route(route, name, [callback])

Manually create a route for the router, The route argument may be a routing string or regular expression. Each matching capture from the route or regular expression will be passed as an argument to the callback. The name argument will be triggered as a "route:name" event whenever the route is matched.

">navigate router.navigate(url, [mode, data, options])

Whenever you reach a point in your application that you'd like to save as a URL, call navigate in order to update the URL. If you wish to not call the route function, set the trigger option to false.

">start router.start()

Start the router to listen to url changeemnt.

<%= view.component("code", {code: "router/route.js", run:true}) %>

">Urls

The module Urls gives access to methods to simply calculate application urls.

">base hr.urls.route(*args)

Return complete url in the application using the configuration variable baseUrl.

<%= view.component("code", {code: "urls/base.js", run: true}) %>

">static hr.Urls.static(*args)

Return complete url in the application for a content in the static directory using the configuration variable staticDirectory.

<%= view.component("code", {code: "urls/static.js", run: true}) %>

">route hr.Urls.route(route, args, [base])

Return complete url in the application for a route and the route arguments using the configuration variable router.mode.

<%= view.component("code", {code: "urls/route.js", run: true}) %>

">extendRules hr.Urls.extendRules(rules)

Extend urls rules of module Urls.

<%= view.component("code", {code: "urls/rules.js", run:true}) %>

">In templates

Module Urls is accessible in templates using hr.urls.

<%= view.component("code", {code: "urls/template.html"}) %>

">Internationalization (i18n)

The module I18n gives an easy way to manage different languages for your application.

">loadLocale hr.I18n.loadLocale(lang)

Load translation corresponding for the language lang.

<%= view.component("code", {code: "i18n/load.js", run: true}) %>

">translate hr.I18n.t(scope, [options])

Return the translation for scope. The translation string is parsed like a template using options.

The translations tables is something like that :

<%= view.component("code", {code: "i18n/en.json"}) %>

">In templates

Module i18n is accessible directly in the template using hr.I18n.

<%= view.component("code", {code: "i18n/template.html"}) %>

">Storage

The module Storage is a simple interface to the navigator localStorage.

It supports storage of complex object and not just string.

For gestion of cached values or resources, use instead module ">Cache.

">get hr.Storage.get(key)

Return a value stored in the localStorage.

">set hr.Storage.set(key, value)

Define a value to store in the localStorage.

">remove hr.Storage.remove(key)

Remove a value from localStorage.

">clear hr.Storage.clear()

Clear all the values stored in the localStorage.

">usedSpace hr.Storage.usedSpace()

Return the number of value stored in localStorage.

">Cache

The module Cache use the module ">Storage to storage content for a timelapse.

The good way to use caching is to use ">Cache.namespace.

Cache can store any json-serializable value to any json-serializable key. Cache stored key is relative to the application build revision.

<%= view.component("code", {code: "cache/key.js"}) %>

">get hr.Cache.get(namespace, key)

Return a value stored in the Storage.

">set hr.Cache.set(namespace, key, value, expiration)

Define a value to store in the Storage for a timelapse.

expiration define the timelapse in seconds, if expiration <‹ 0 then value don't have a timelife.

">remove hr.Cache.remove(namespace, key)

Remove a value from Storage.

">clear hr.Cache.clear()

Clear the all cache without clearing the all Storage.

">namespace hr.Cache.namespace(namespace)

Return a cache interface centered arround a namespace.

<%= view.component("code", {code: "cache/namespace.js", run: true}) %>

">Resources

The module Resources let you load resources (such as templates, ...) in a standart way.

">load hr.Resources.load(namespace, ressource)

Load a ressource in a namespace and return a ">Deferred.

<%= view.component("code", {code: "resources/load.js", run: true}) %>

">addNamespace hr.Resources.addNamespace(namespace, options)

Add a namespaces for resources with options for loading.

<%= view.component("code", {code: "resources/namespace.js", run: true}) %>

">addLoader hr.Resources.addLoader(name, handler)

Add a new loader for loading resources.

Base loader are :

  • http : Load resources using http requests and caching
  • require : Load resources from application source code using require

<%= view.component("code", {code: "resources/loader.js", run: true}) %>