Conventions Client API Server API Architecture Getting Started

Packages

The Sapphire framework has a concept called packages. A package is a namespace for classes. By putting new classes into packages, it frees the global name space, and permits organizing classes by functional groupings. For example, the package Horizon.Controllers could hold all of the application’s controller classes, and Horizon.Views could hold all the applications view classes. When this is the case, you can have classes with the same name but in different packages, such as Horizon.Controllers.Admin and Horizon.Views.Admin.


Package

This function opens a package to add new members. Use this to defile new classes.

function Package(name, members)
Parameters
nameName of the package – use dot notation to nest pakages for example Horizon.Views
membersObject that contains the new members to add to this package
Example
Package('Horizon.Controllers', {
    Admin : new Class({
        Extends : Sapphire.Controller,
    }
});

Import

Call this function to get a reference to a package. This is handy if you need to reference a number of classes in the same package. Rather than using the full name, you can use the imported package.

function Import(name)
Parameters
nameName of the package to be imported, using dot notation
Example
var views = Import('Horizon.Views');

...

this.ListView = new views.List();

Global Variables

The framework declares two global variables. One is SAPPHIRE which is used as a name space for a number of framework objects, such as the application object. The other variable is the namespace declared in the server-side Application class. The namespace is used to hold the application defined variables added while building the HTML.

Sapphire.Eventer Class

Use the Eventer class to listen for and fire events. This class is used internally by the Sapphire classes, such as Application. To add eventing to your own classes, you should extend them from this as a base class.


listen

Call this method to register a listener for an event.

listen : function(name, callback)
Parameters
nameName of the event to listen for
callbackFunction to call when the event is fired
Returns
This function returns a unique identifier that can be used to remove the event listener

fire

Call this method to fire an event. All registered event handlers will be called in the order they were added.

fire : function(name, ...)
Parameters
nameName of the event to fire
...Any additional parameters are passed to the event handlers

remove

Call this function to remove a previously registered event handler.

remove : function(name, id)
Parameters
nameName of the event
idValue returned from listen

Sapphire.Application Class

The application class on the client is different from the Application class on the server. Whereas the server Application class revolves around constructing the HTML for the application, the one on the client is used to manage the application space. There is a single instance of the application class created by the framework, SAPPHIRE.application.

Some of its primary functions are the management of pages, dialogs and panels.

Pages
Pages appear in a fixed area of the application specifically reserved for them. The application object assumes there is a DOM node with the Id of ‘pages’ and will use this node to display the active page. <br><br>An individual page is a specification of the html that will occupy the pages area of the application, along with all the assets necessary to render the page and perform the necessary functions it represents.
Dialogs
Dialogs are similar to pages, and they are specified the same way. However, dialogs are designed to be modal, and to be displayed over the rest of the application. Also, more than one dialog can be displayed at any given time, whereas pages can only have one active at a time.
Panels
Panels are sort of like pages, except that you can create multiple panel sets, each set being displayed in a different region of the application. Panels are specified in the same way as pages and dialogs, and like them are hot loaded. <br><br>In addition to pages and dialogs, the Application class also acts as a registry for global model, views and controllers. And perhaps most importantly, it controls the application startup flow and the hot-loading flow.
Startup FlowTwo key events are fired during the application start and ready
startThis is fired before any pages or dialogs are displayed, but after the DOM is fully loaded. This method can be used to delay full application startup until some prerequisite action has taken place, for example, an intercessory ad. When the start event is fired, a callback function is passed to the event listeners. The ‘ready’ event will not be fired until every listener to ‘start’ has called this method
readyThis is fired when the start events have all finished. This is the signal that everything is ready to go, and pages can now be displayed, and normal operation can proceed.
Hot Loading FlowThere are two key stages of hot loading, the load itself and the showing of the page, dialog or panel that was hot loaded. The following events are fired during hot loading.
loadThis is fired when all the resources for a hot-loaded object have been loaded, this includes the HTML, the CSS and the JavaScript. The HTML for the page is in the DOM when this event is fired.
showThis is fired every time the hot-loaded object is displayed using an application showXXX method.
firstShowThis is only fired the first time the object is shown.

showPage

Call this method to hide the current page and show a new one. If the current page has not been marked as dontPrune, then it will be removed from the DOM. Before the page has been removed, any hide events will be fired. The show events will be fired once the page has been added back into the DOM.

showPage : function(name, ...)
Parameters
nameName of the page
...Any arguments passed after name will be passed to any show listeners for this page

showDialog

Call this method to show a dialog. Any dialogs already shown will remain shown. Show events will be fired once the dialog has been added back into the DOM. Dialogs are modal elements, and must be completed before the application can proceed.

showDialog : function(name, ...)
Parameters
nameName of the dialog
...Any arguments passed after name will be passed to any show listeners for this dialog
Returns
This returns a Q promise. A deferred is passed as the first parameter to the show listeners, and they can use this deferred to fulfill the promise with the result of the dialog.

For example, if the dialog is intended to solicit the click of a yes or no button, then when one of the buttons is clicked, the deferred’s resolve method can be called with an indication of which button was clicked. This will fulfill the promise and its then method will be called.

SAPPIRE.showDalog(‘yesno’, ‘Do you really want to take a nap’)
    .then(function(which)
    {
        if (which == ‘yes’) alert(‘ZZZZZZZZzzzzzzzzzzzz’);
    });

hideDialog

Call this method to hide a dialog. This method must be called to dismiss a dialog, it will not be called automatically.

hideDialog : function(name)
Parameters
nameName of the dialog to hide

showPanel

Call this method to hide the current panel in the given set and show a new one. Before the panel has been removed from the DOM, any hide events will be fired. The show events will be fired once the page has been added back into the DOM.

Parameters
setName of the panel set, defined when the panels were added in the server code
nameName of the panel
...Any arguments passed after name will be passed to any show listeners for this panel

setPanelContainer

Call this method to set the region of the application that will receive the panels of the given panel set

setPanelContainer : function(set, selector)
Parameters
setName of the panel set, defined when the panels were added in the server code
selectorjQuery selector for the region to display the panels

listenPageEvent

Call this method to listen for a page specific event.

listenPageEvent : function(event, which, callback)
Parameters
eventName of the event being listened for, for example, show
whichWhich page you are listening to – if this string is empty, it will listen to all pages
callbackFunction to call when the event is fired

listenDialogEvent

Call this method to listen for a dialog specific event.

listenDialogEvent : function(event, which, callback)
Parameters
eventName of the event being listened for, for example, show
whichWhich dialog you are listening to – if this string is empty, it will listen to all dialogs
callbackFunction to call when the event is fired

listenPanelEvent

Call this method to listen for a panel specific event.

listenPanelEvent : function(event, set, which, callback)
Parameters
eventName of the event being listened for, for example, show
setThe name of the panel set, defined when the panels were added in the server code
whichWhich panel you are listening to – if this string is empty, it will listen to all panels
callbackFunction to call when the event is fired

registerController

Call this method to register a global controller. When a controller is registered, other controllers can find it to call its methods.

registerController : function(name, controller)
Parameters
nameName this controller should be indexed on
controllerConstructed controller object – controllers generally inherit from Sapphire.Controller

registerView

Call this method to register a global view. When a view is registered, other views can find it to call its methods.

registerView : function(name, view)
Parameters
nameName this view should be indexed on
viewConstructed controller object – controllers generally inherit from Sapphire.View

registerModel

Call this method to register a global model. When a model is registered, other models can find it to call its methods.

registerModel : function(name, model)
Parameters
nameName this model should be indexed on
modelConstructed controller object – controllers generally inherit from Sapphire.Model

getController

Call this method to get a previously registered controller.

getController : function(name)
Parameters
nameName of the desired controller – one that was passed to registerController
Returns
Controller instance

getView

Call this method to get a previously registered view.

getView : function(name)
Parameters
nameName of the desired view – one that was passed to registerView
Returns
View instance

getModel

Call this method to get a previously registered model.

getModel : function(name)
Parameters
nameName of the desired model – one that was passed to registerModel
Returns
Model instance

Sapphire.Templates Class

Use the templates class to manage templates, which are DOM nodes that can be reused, mostly useful for partials. These nodes are removed from the DOM at start up and when HTML is hot loaded for pages, dialogs and panels. To specify the HTML for a template, add the class template to the HTML element that is the template. The id of that element will be used to reference that template in your JavaScript. To use templates, your application needs to add the JavaScript file /assets/js/lib/templates.js.

There is one instance of the templates class, SAPPHIRE.templates.


get

Call this function to get a copy of your template

get : function(which)

The following code shows an example of using templates.

draw : function(users)
{
    var container = $('#user-list');
    container.empty();
    users.each(function(user)
    {
        var template = SAPPHIRE.templates.get('user-item');

        template.find('#username').html(user.identity.name);
        template.find('#edit-user-button').click(this.fire.bind(this, 'editUser', user));

        container.append(template);
    }, this);
}

Sapphire.History Class

The history class manages the web client url to support both deep linking and the back button. It uses a URL hash. Each page switch generates a new URL, and hitting the back button will automatically switch to the previous page. If using the history functionality, the only parameter that should be passed to SAPPHIRE.application.showPage should be an object that represents a pseudo query string. Only numbers and strings should be in this object. The query string will be appended to the hash part of the url. An example url hash might be #profile?user=10009. This would be the result of calling this code.

SAPPHIRE.application.showPage('profile', {user: 10009});

When a page is replayed with the back button, this same function will be called by the history class. To use the history class, your application needs to add the JavaScript file /assets/js/lib/history.js.

There is only one instance of this class, SAPPHIRE.history. It has no callable methods.

Sapphire.Services.AjaxService Class

There are two kinds of services, socket based, and AJAX based. The service handler classes are written as mixins, so the application can create its own services object that includes the desired functionality. The general rule is that there is only a single service instance, which can be hooked by anybody who wants to examine the service result for global changes. For example, we have the following code from a model object that looks for any changes in the login state, and fires an event if found.

HORIZON.service.listen('ajaxResponse', this.onServiceResponse.bind(this));

...

onServiceResponse : function(response)
{
    if (response.identity != undefined)
    {
        this.identity = response.identity;
        HORIZON.identity = this.identity;
        this.fire('identityChange', response.identity);
    }
}

The following example shows how to integrate this mixin class with an application defined service class. Notice that the service class must extend the Eventer class, as the AjaxService class fires events.

Package('Horizon', {
    Service : new Class({
        Extends : Sapphire.Eventer,
        Implements: [Sapphire.Services.AjaxService],
        initialize : function()
        {
            this.parent();
            this.initializeAjaxService()
        }
    })
});

HORIZON.service = new Horizon.Service();

call

Call this method to send a service request to the server-side code. Calls to this method are generally handled through a model class.

call : function(url, data, method, type)
Parameters
urlThe url of the service to call – this must follow the conventions documented earlier in this document
dataObject with all the data that should be sent to the service – it should be a single level, with simple types and can contain arrays of simple types
methodHTTP method, one of GET, POST, PUT or DELETE
typeSpecifies the type of return data expected, or the manner of its return – the default is json
Returns
Returns a Q promise that will be resolved when the service completes

Sapphire.Services.SocketService Class

This is the implementation of the socket services. The sapphire framework can be configured to listen for socket events, this is the client side API to call those socket services.


setupSocketServer

Call this method is your socket class’ initializer to set up the server that should be used for socket messages.

setupSocketserver : function(server)
Parameters
serverthe url of the server to use for socket messages

message

Call this method to send a socket message to the server. The socket message will be passed a callback, which is expected to return a single result. This method returns a promise that will be resolved with that result.

message : function(path, data)
Parameters
pathThe message path. This is expected to follow this format <application>/<object>/<message>
dataData to be passed to the message handler
Returns
A promise that will be fulfilled with the message result

socketListen

Call this method to listen for an asynchronous message from the server. There is a limitation of one listener per message. This limitation will be removed.

socketListen : function(what, callback)
Parameters
whatA string representing the message being sent
callbackFunction to call when the message is received

Translation

There are two inputs to the translation service, one is the list of strings that need to be translated, and the other is a list of global lookup strings that can be used in translated text. To specify this data, the translation class looks for two global variables, translations and lookups.

The translations variable is an object where the name of each element is the source string in English, and the value is the translated text

The lookups variable is an object that contains the global lookups for translations. Lookups are strings that appear in curly braces in a translation, for example, please place the {thing} on the {surface}. Lookups are frequently specific to the individual strings being translated, but sometimes they represent some sort of global variable, such as user name, Hello {name}. The name of each element in this object is the name of the lookup and the value is the string to use to replace it.

There are two ways that strings can be translated, one is in the html source, and the other is in code. In the HTML source there will frequently be a number of strings such as labels and menu items that need to be translated. To translate these strings add the class .translate to the element.

The other way is to translate in code. To do so, use the _T function.

Another thing to note is that strings to be translated should never be constructed piecemeal. All translated strings should form a complete sentence. This is because the grammar of a language will not necessarily follow the same rules as English.

To use the translation facility your application needs to add the JavaScript file /assets/js/lib/translate.js.


_T

Call this function to get the translation for a string.

function _T(text, replacements)
Parameters
textFull text to be translated
replacementsObject containing the values of any replacements in the string that are not in the global replacement list
Returns
The translated string
Example
$('#message').html(_T('please put the {object} on the floor', {object: 'football'}));

Marklar Query String

To facilitate translation verification there is a query string parameter that can be added that will affect the way translations are performed. This parameter is called marklar and can take these values.

marklar
subAll replacement text will be replaced with the string marklar – use this to test for global replacements that are missing
rawAll strings that are translated will be replaced with the string marklar - use this to find untranslated strings