Building a Titanium JavaScript library
As were finally starting to get some real hands-on experience in Titanium application creation, we've now amassed a fair share of tools to ease the process. The Titanium API is very low level - which is as it should be, but it can at times feel more than just a little clunky. Getting around that is as simple as abstracting away the parts you don't like, which has resulted in our own Krawaller JavaScript framework sitting on top of Titanium. Its nowhere near all-covering, life-altering or complete, but some ideas have come far enough to be thrown at the community, to see what comes back. :)
Below are a few examples of things we've done to ease the process. I'm sure there are several similar and presumably superior wheels invented all over the place - don't hesitate to share your own efforts in the comments!
Element creation logic
We have wrapped all element creation through our own K.create function. The argument object will, apart from the normal parameters passed on to Titanium, have a type and a children property. The type is of course the type of native element, and children is an (optional) array of subelements to be contained within the created element. The create function will recursively call itself and add these to the returned object. This enables us to for example create a TableView like this:
We're also sprinkling some convenience logic throughout this function - for example, children of a tableview or tableviewsection are assumed to be tableviewrows if no type is specified, enabling us to leave that property out if it is a row we want.
Created elements are also given access to the object that created them, meaning we can later on access the id property in the above example within a clickhandler set on the rows.
Styling native elements
Another advantage of wrapping the native creation functions is that we can centralise the element styling. A call to our create function results in the execution of something like this:
The K.merge function simply merges all arguments together into one object, giving precedence to leftmost properties. Thus, the object you pass in to the create function is always king of the hill, and the options you leave out will get its values from the preset defaults.
Those values all reside in one single object, where it is very easy to quickly give the whole application a different set of clothes:
The url-specific defaults are used when creating windows, allowing us to specify specific styles for different pages.
Webviews
Most of the work, however, went into the webview creation function. While recently working on the official Tristania application we needed several different webviews with slightly different properties, which made the code everything but DRY. With the framework in place, however, a single statement sufficed for each webview:
The argument object has two properties; the name of the template file, and a data object that will be supplied to that template. You can also optionally specify a masterpage, if you don't want the default one to be used.
The call to the creation function takes care of everything, leaving that single execution line in the application code. Here's the definition of the webview creation function:
A template file looks like this:
Being able to write JavaScript logic inbetween the html tags greatly simplifies adding custom behaviour depending on the data.
The master page is a full html document, into which the template will be injected and rendered:
This system has several advantages:
- The code will be far less dry, and each webview template need only contain the actual html used.
- Styling is centralised to the masterpage, enabling you to have a global css file linked at one single place. Should a template need specific styling, you can simply add that in a style tag within the template itself, as in the previous biography template example.
- You also control the rendering of all webviews. This masterpage contains a neat effect where all webviews are initially transparent, but will fade into full opaqueness when it has finished rendering. This looks nice, and prevents the user from seeing it rendered bit by bit.
Going forward
Our plan was never to build a full framework, but putting our various convenience functions together and making then conform has started to amount to the same thing. We're not committing to any "soon" promises, but definitely plan to share what we end up with. I'm not sure a single, jQuery-style-all-conquering framework is what the Titanium community needs, but we could definitely benefit from sharing what we've done to make everyday Titanium life easier. Perhaps this is one way of accomplishing that?
4 comments
For instance
DataBase and FileSystem are wrapped in your framework. Your app only uses DataBase. Will the filesystem module also be compiled into your app?
Reason being is that I am wanting to create a framework for my own company that will make rolling out new apps a lot faster. Each app will have use different features so I'd prefer if it didn't compile the modules that were not in use by the app, even if they are part of the framework.
Also I'm not sure whether we'll reach a size where splitting it up is worth the complexity of a build process.
That said, we'll most likely package it using a sandbox pattern anyway, where each window need only instantiate what's needed (since there is no "super-global context" in Titanium, every window context using the Krawaller functions has to instantiate its own copy).
And if we should choose not to do this, you'll be free to take the code and have it your way anyway. :)
Great work, thanks for sharing.
http://gist.github.com/488533
I just copy-pasted without testing, so holler if something is broke or missing! Or snoop around in the Tristania app repository here: http://github.com/krawaller/Tristania