10 Jan

PhoneGap + JavascriptMVC + jQuery Mobile

I started a new mobile app project and decided to go with HTML5 wrapped with PhoneGap. The reasons are many and this post isn’t about why, but how.

Before you start, here are the libraries/frameworks I am using:
jQuery Mobile – a “Touch-Optimized Web Framework for Smartphones & Tablets”
Javascript MVC – a Javascript MVC Framework (and more)
PhoneGap – “HTML5 app platform”/embedded cross platform browser

I will be posting code snippets as I go along that may be helpful to someone just starting out with a similar project.

Here is my directory structure so far:

  • blocks
    • controllers
    • views
    • blocks.js
  • pages
    • controllers
    • views
  • models
    • models.js
    • blog_post.js
  • css
  • images
  • platforms // platform projects (iOS XCode project, Android eclipse project, etc.)
  • myapp.js
  • myapp.html
  • build.xml

I also chose to go with EJS for the templating system which allows my view to look very similar to a PHP/Zend Framework view:

<%== blocks('header') %>
<div data-role="content" id="frontpageContent">
    <ul data-role="listview" data-theme="c">
        <% if (items) for(var i=0; i < items.length; i++) { %>
            <li data-icon="tcc2-arrow-right">
                <a href="#">
                    <img src="<%= items&#91;i&#93;.media.m %>"/>
                    <h3><%= items&#91;i&#93;.title %></h3>
                </a>
            </li>
        <% } %>
    </ul>
</div>
<%== blocks('footer') %>

The first piece of code that makes life a little easier on large projects is my blocks view helper. This way I can modularize and reuse:

    $.EJS.Helpers.prototype.blocks = function (blockName) {
        if (typeof MyApp.Blocks[blockName] === 'function') {
            blockInstance = new MyApp.Blocks[blockName]($('<div/>'));
            return blockInstance.view;
        }
        throw "No such block controller MyApp.Blocks." + blockName;
    }

You could also just call

<%== $.View('someview.ejs') %>

if you have no need for a controller. Block controllers look like this:

$.Controller('MyApp.Blocks.Header',
    /** @Static */
    {
        defaults: {},
        pluginName: 'header'
    },
    /** @Prototype */
    {
        init : function(){
            this.view = $.View("my_app/blocks/views/header.ejs",{});
        }
    }
); // Header controller

Now on to more substantial jQuery Mobile related code. We need jqm navigation to tie into our MVC controllers and vice versa. In other words, when we navigate to #frontpage, we want a new page injected into our dom using the frontpage controller, which in turns will render a view (frontpage.ejs, or init.ejs if you stick to the generated naming).

The answer to this problem comes straight from the jQm manual:
From myapp.js (or whatever you called your app)

steal(
    'phonegap-1.3.0.js',
    'jquery/jquery.js',
    './css/jquery.mobile.structure-1.0.min.css' // jQuery Mobile structure CSS
    )
.then(
    './css/global.css', // Our global css style and jqm theme
    'jquery/controller',
    'jquery/view/ejs'
    )
.then(
    './models/models.js', // all models
    './pages/pages.js', // all pages
    './blocks/blocks.js', // all blocks and Blocks view helper
     function () { // Init some jqm settings and fadeIn splash page
        $(document).bind("mobileinit", function(){
            $.mobile.touchOverflowEnabled = true;
            $.mobile.allowCrossDomainPages = true;
        });
    })
.then('//library/jquery.mobile-1.0.min.js') // jQuery Mobile library
.then(
    // Run the frontpage controller
    function() {
        $('#splash').fadeIn(500);
        // intercept changePage events to inject our controllers as needed (dispatch)
        $(document).bind( "pagebeforechange", function( e, data ) {
            // we only handle url changes
            if ( typeof data.toPage === "string" ) {
                // We are being asked to load a page by URL
                var u = $.mobile.path.parseUrl( data.toPage ),
                    re = /^\#([a-zA-Z]+)$/;

                if (u.hash.search(re) !== -1 ) {
                    var $page = re.exec(u.hash);
                    $page = $page[1];
                    console.log('Loading page ' + $page);
                    // We're being asked to display the items for a specific page
                    // Call our internal controller
                    if (typeof MyApp.Pages[$page] === 'function') {
                        var controller = new MyApp.Pages[$page]( $('body') );
                        controller.view.done(function (htmlOutput) {
                            $(htmlOutput).appendTo( $('body') ).page();
                            $.mobile.changePage( $(htmlOutput) );
                        });
                    }
                }
            }
        });
        setTimeout(function () {
            $.mobile.changePage('#frontpage');
        }, 500);
    });

This is of course a very early draft, but I hope it is enough to fill in the gaps between the docs of JMVC and jQm to get someone started. There is much you need to add to make this nicer. For example you could have an routes object defining each hash and params and which controller to send them to, then use that during the event above (look at jquery page params for adding hash params to jQuery Mobile).

06 Aug

Macbook battery woes

My Macbook’s battery is finally dead, which means the book shuts down immediately if I unplug it from power. I accidentally pulled on the power cable yesterday, and as a result my usually rock solid Leopard OS started showing me instability of applications, and eventually the dreaded screen of death.

Luckily, I have time machine running and backing up everything. I rebooted on the OSX install disk, ran a repair disk through the Disk Utility, then restored a couple of the Application Support folders under my user folder that I found to have been corrupted (mostly stuff I had running at the time of the crash: Firefox, Mail, VLC, iTunes, etc.)

I am glad time machine worked as advertised. My last backup was done at noon, and the crash at 2PM so I haven’t lost anything.

07 Jan

Cheap IT to start a business (Part 2)

Friends ask me all the time: how much would it cost to start a business from an IT perspective, as in get a website, get email, phone numbers, an ERP system, a CRM system, some basic automation, etc. This makes non-techies very nervous when just starting out on the cheap. Word on the street is that these things cost millions. Interestingly enough, most people don’t know that they can do most of that expensive stuff for next to nothing, and a little elbow grease.

This article is not meant as an in depth how-to but more as an example of what you can get done with a little knowledge when just starting out.

Click here if you’ve missed Part 1 of this article

Read More

10 Dec

Cheap IT to start a business (Part 1)

Friends ask me all the time: how much would it cost to start a business from an IT perspective, as in get a website, get email, phone numbers, an ERP system, a CRM system, some basic automation, etc. This makes non-techies very nervous when just starting out on the cheap. Word on the street is that these things cost millions. Interestingly enough, most people don’t know that they can do most of that expensive stuff for next to nothing, and a little elbow grease.

This article is not meant as an in depth how-to but more as an example of what you can get done with a little knowledge when just starting out.

Read More

13 Nov

Burney Falls Video

This is another video I took of Burney Falls. Taken with my Panasonic Lumix DMC-LX2 at 1280×720, 15fps.

[flashvideo filename=http://s3.amazonaws.com/YacineFilali/P1000794.flv /]