Building an HTML5 Mobile App using jQuery Mobile and ASP.NET MVC

The mobile revolution has created a plethora of new platforms and languages. It is rare to see old technologies successfully reaching new grounds together. A good example of this is .NET MVC and jQuery Mobile. The blends of Razor, HTML, CSS, and jQuery make mobile a very familiar territory, a package that makes things quick, easy, and beautiful!

Setup the Project

The first thing you want to do is fire up Visual Studio and create a new MVC 3 Internet Application. This will give you membership, templates, and sample content to your website with a single click. Our goal from here is to extend it to a mobile site. To make this more interesting though, let us make it iPad optimized as well.

Add NuGet Package

To help with the device detection, we will be using the open source .NET project called 51Degrees.Mobi. It extends the "Request.Browser" object by getting information from the Wireless Universal Resource File (WURFL) – one of the most comprehensive and up-to-date databases of mobile device information. This will allow us to find out what smartphone or tablet the user is using. 51Degrees.Mobi is also available as a NuGet package, so "Add this Library package" to your Visual Studio project.

One thing to note here, by default the 51Degrees.Mobi package uses a simple redirection to the "~/Mobile" folder to get you started - quick, dirty, and probably more relevant for Web Forms. For our purpose though, let us redirect views not URL's to keep things MVC-licious. This means deleting the new "~/Mobile" folder that was created, as well as removing the <redirect> element inside the <fiftyOne> section in "~/App_Data/51Degrees.mobi.config".

NOTE: The WURFL file that currently comes with the 51Degrees package is a bit outdated and does not recognize iPad2 devices. Under "~/App_Data", update "wurfl.xml.gz" and "web_browsers_patch.xml" from WURFL's latest repository to correct this.

MVC Controllers

Now let us move on to the controllers. In the HomeController, add the below condition statement in the Index action. This will pass mobile devices to another controller:

public ActionResult Index()
{
    ViewBag.Message = "Welcome to ASP.NET MVC!";

    //HANDLE MOBILE DEVICE IF APPLICABLE
    if (Request.Browser.IsMobileDevice)
    {
        return RedirectToAction(null, "Mobile");
    }
    else
    {
        return View();
    }
}

The code above expects a MobileController. So right click on the "~/Controllers" folder and add a controller called "MobileController". Once the class opens, modify the Index action with the below code:

public ActionResult Index()
{
    return View(MobileUtils.GetViewName());
}

Fine Tuning Device Detection

How does "MobileUtils.GetViewName" know what view to use based on device? We have to create a nifty static utility! Create a new folder called "~/Utilities" and add a new class called "MobileUtils". Paste the below method there:

public static string GetViewName()
{
    var context = HttpContext.Current;
    string viewName = null;

    if (context != null && context.Request.Browser.IsMobileDevice)
    {
        //GET MANUFACTURER OF DEVICE
        string manufacturer = context.Request.Browser.MobileDeviceManufacturer.ToLower().ToString();
        string model = context.Request.Browser.MobileDeviceModel.ToLower().ToString();
        bool isTablet = Convert.ToBoolean(context.Request.Browser["is_tablet"] ?? "false");

        //HANDLE TABLE IF APPLICABLE
        if (isTablet)
        {
            //FOR IPAD AND OTHER TABLETS
            viewName = "Tablet";
        }
        else
        {
            //DETERMINE VIEW NAME BASED ON DEVICE
            switch (manufacturer)
            {
                case "apple":
                case "android":
                case "windows":
                case "nokia":
                case "rim":
                default:
                    viewName = "Index";
                    break;
            }
        }
    }

    return viewName;
}

The "GetViewName" method uses the new 51Degrees.Mobi helpers to figure out the view name to return based on the user's device. Notice the manufacturer, model, and is_tablet variables can be used to determine this. The code is a little stubbed out in case you want to extend it per device.

MVC Views

Now we can start to create views per device, but first let us create a template for the mobile pages. This will contain the HTML5 template needed for jQuery Mobile to work. Under the folder "~/Views/Shared", create a new view called "_LayoutMobile" and paste the below content in there. This uses the hosted jQuery Mobile scripts and styles which contains all the magic.

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="http://code.jquery.com/mobile/latest/jquery.mobile.min.css" rel="stylesheet" type="text/css" />
    <script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>
    <script src="http://code.jquery.com/mobile/latest/jquery.mobile.min.js" type="text/javascript"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
    @RenderBody()
</body>
</html>

NOTE: I also created "_LayoutTablet" in my sample solution to take advantage the jQuery Mobile Splitview plugin for tablets.

With the new mobile layout in place, create the default mobile view by right clicking on the Index action and add a view. Choose the new mobile layout that was just created.

This will be the view used for "generic" mobile devices. Create a new view called "Tablet" under the "~/Views/Mobile" folder in the same way (use _LayoutTablet if you created one). This will be specifically sent to tablets, such as iPad's, which is determined from the MobileUtils.GetViewName method.

This takes care of the MVC side of things. It should be straight HTML5 and jQuery Mobile from here!

jQuery Mobile

Let me pause for a minute and give a brief explanation of what jQuery Mobile is and how to use it. First let me rid your fears; you only need to know HTML markup to use jQuery Mobile! There is little reason to touch CSS and even jQuery. All you have to do is decorate your HTML markup with attributes and classes - and that's it! By using HTML5 data-* attribute and CSS classes, jQuery Mobile determines the role and properties of the elements, then automagically adds styles and modifies the markup from there. Check out this sample:

<div data-role="page">

<div data-role="header">
<h1>Page Title</h1>
<a href="#" data-icon="search" class="ui-btn-right" data-iconpos="notext">Search</a>

</div><!-- /header -->

<div data-role="content">
<p>Page content goes here.</p>
<div data-role="controlgroup"> <a href="index.html" data-role="button">Link 1</a> <a href="index.html" data-role="button">Link 2</a> <a href="index.html" data-role="button">Link 3</a> </div>
</div><!-- /content -->

<div data-role="footer">
<h4>Page Footer</h4>
</div><!-- /footer -->
</div><!-- /page -->

What a beautiful interface layer! Instead of forcing you to procedurally create the interface like other mobile web frameworks (ehhmmm Sencha), jQuery Mobile goes with the natural flow of web concepts, such as HTML5, CSS3, and jQuery. The anatomy of a jQuery Mobile page can be seen above. It contains a "div" wrapper defined with the data-role="page" attribute. This acts like the "body" of mobile page. "Pages" will contain "div" children that have their own data-role attributes. Some data-role examples include "header", "content", "footer", "navbar", "listview", "button", and more. There are other data-* attributes and CSS classes available for the jQuery Mobile framework, such as data-position="fixed", data-theme="b", data-icon="gear", class="ui-btn-right", and others.

Interface for Mobile Devices

Now armed with this knowledge, open up the Mobile/Index view and paste the below markup:

@{
    ViewBag.Title = "Mobile Dashboard";
    Layout = "~/Views/Shared/_LayoutMobile.cshtml";
}

<div data-role="page">

    <div data-role="header">
        <h1>@ViewBag.Title</h1>
	    <a href="#" data-icon="star" class="ui-btn-left">Profile</a>
	    <a href="#" data-icon="search" class="ui-btn-right" data-iconpos="notext">Search</a>
    </div>

    <div data-role="content">
        <ul data-role="listview">
            <li data-role="list-divider">Comments unread <span class="ui-li-count">47</span></li>
            <li>
                <div data-role="navbar">
	                <ul>
		                <li><a href="#" data-icon="grid">Blogs</a></li>
		                <li><a href="#" data-icon="grid">Gallery</a></li>
		                <li><a href="#" data-icon="check">News</a></li>
		                <li><a href="#" data-icon="star">Events</a></li>
		                <li><a href="#" data-icon="grid">Surveys</a></li>
		                <li><a href="#" data-icon="check">Polls</a></li>
		                <li><a href="#" data-icon="star">Store</a></li>
		                <li><a href="#" data-icon="home">Forums</a></li>
		                <li><a href="#" data-icon="star">Tweets</a></li>
		                <li><a href="#" data-icon="grid">Contact</a></li>
	                </ul>
                </div>
            </li>
        </ul>
    </div>

    <div data-role="footer">
        <div data-role="controlgroup" data-type="horizontal">
            <a href="#" data-role="button" data-icon="info" data-iconpos="notext" data-inline="true">Info</a>
            <a href="#" data-role="button" data-icon="gear" data-iconpos="notext" data-inline="true">Options</a>
        </div>
    </div>

</div>

Interface for Tablet Devices

Next open the Mobile/Tablet view and paste the below markup:

@{
    ViewBag.Title = "Tablet Dashboard";
    Layout = "~/Views/Shared/_LayoutTablet.cshtml";
}
<div data-role="panel" data-id="menu" data-hash="crumbs" data-context="a#default">
    <!-- Start of first page -->
    <div data-role="page" id="main">
        <div data-role="header" data-backbtn="false">
            <h1>
                Main</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <ul data-role="listview" data-theme="g">
                <li>About
                    <ul>
                        <li><a href="#aboutsv" data-panel="main">About Splitview</a></li>
                        <li><a href="#secondarypage" data-panel="main">Secondary Page</a></li>
                    </ul>
                </li>
                <li>Features
                    <ul>
                        <li><a href="#panels" data-panel="main">Panels</a></li>
                        <li><a href="#orientation" data-panel="main">Orientation</a></li>
                        <li><a href="#scroll" data-panel="main">Scroll</a></li>
                        <li><a href="#context" data-panel="main">Context Loading</a></li>
                    </ul>
                </li>
                <li><a href="#page3" data-panel="main">Page 3</a></li>
                <li><a href="#page4" data-panel="main">Page 4</a></li>
            </ul>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 2nd page -->
    <div data-role="page" id="demo">
        <div data-role="header" data-backbtn="false">
            <h1>
                Demos</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <ul data-role="listview" data-theme="g">
                <li><a href="#bar" data-panel="main" id="default">Bar</a></li>
                <li><a href="#badz" data-panel="main">badz</a></li>
                <li>First level list
                    <ul>
                        <li>Second level list
                            <ul>
                                <li><a href="#bar" data-panel="main">long list test</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                                <li><a href="#badz" data-panel="main">badz</a></li>
                            </ul>
                        </li>
                        <li><a href="#bar" data-panel="main">Bar</a></li>
                        <li><a href="#badz" data-panel="main">badz</a></li>
                    </ul>
                </li>
            </ul>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
</div>
<!-- panel menu -->
<div data-role="panel" data-id="main">
    <!-- Start of 6th page -->
    <div data-role="page" id="aboutsv">
        <div data-role="header">
            <h1>
                About SplitView</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                This is the <a href="https://github.com/asyraf9/jquery-mobile/" target="_blank">jQuery
                    Mobile Splitview plugin</a> that renders splitview pages accordingly to tablet
                devices, e.g. iPad. Hopefully the "splitview" component makes it to the core jQuery Mobile
                framework instead of remaining an unsupported, 3rd party plugin.</p>
            <h2>
                Features</h2>
            <ul>
                <li>auto-detection of how to render for the browser you are using.</li>
                <li>independent panel scrolling (still a lot more to work on here)</li>
                <li>orientation and resize aware - renders the side panel in a popover fashion when
                    in portrait mode</li>
                <li>context awareness - can be programmed so that opening a page on the side panel also
                    opens a page on the main panel</li>
                <li>deep-link (and history) awareness - linking to a specific page in the main panel
                    works, and hitting on the back and forward button on your browser also works (only
                    for the main panel pages)</li>
                <li>panel specific links - links on the side panel can affect pages in the main panel,
                    or in the side panel itself.</li>
            </ul>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 5th page -->
    <div data-role="page" id="secondarypage">
        <div data-role="header">
            <h1>
                Secondary Page</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <h3>
                Some title</h3>
            <p>
                Fusce a nisi at dolor rutrum tristique. Donec faucibus metus vitae lorem scelerisque
                malesuada scelerisque enim imperdiet. Aliquam in erat orci. Ut ultrices, erat eu
                luctus accumsan, lorem nibh cursus purus, in laoreet nisi tellus interdum sem. Nulla
                fringilla molestie lectus nec hendrerit. In in mollis tortor. Nunc lectus tortor,
                porttitor vitae viverra non, dignissim ac ligula. In tincidunt libero id turpis
                gravida iaculis rhoncus dolor aliquam. Vestibulum congue massa nec nibh sagittis
                tempor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames
                ac turpis egestas. Quisque quis urna arcu. Quisque feugiat ante id turpis ultrices
                vel imperdiet ipsum volutpat. Donec enim magna, pretium eu scelerisque ut, pretium
                placerat risus.</p>
            Sed sed lacinia ante. Aenean non quam in ipsum pharetra condimentum.
            <p>
                Donec turpis lacus, pharetra ac viverra sit amet, lobortis eu nisl. Cum sociis natoque
                penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur porttitor
                dignissim orci ut feugiat. Praesent quis auctor purus. Suspendisse non elit accumsan
                mi pellentesque laoreet. Nullam et sapien sed nibh dictum tempor sit amet ut velit.
                Vestibulum varius ultricies lorem sed ultricies. Vestibulum auctor velit vitae ante
                eleifend eget bibendum metus rutrum. Nulla facilisis luctus mi laoreet rutrum. Nunc
                accumsan urna at elit pellentesque ut venenatis lectus adipiscing. Ut et arcu urna.
                Aliquam eros leo, ultricies vel porta nec, tempor sit amet leo. Quisque imperdiet
                facilisis orci ut malesuada. Nunc eget elit mauris. Mauris sed felis lectus.</p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 7th page -->
    <div data-role="page" id="panels">
        <div data-role="header">
            <h1>
                Panels</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                In order for splitview to work, we defined two more <b>&lt;div&gt;</b> tags to enclose
                the pages - one called 'main', the right hand panel, and 'menu' which is the left
                sidebar panel</p>
            <p>
                This provides us with a few advantages:</p>
            <p>
                1. It allows us to define the area new pages should be loaded in. We do this by
                using data-panel attributes on anchor tags. example:<br />
                <br />
                <b style="padding-left: 30px;">&lt;a href="some_other_page" data-panel="main"&gt;</b>
            </p>
            <p>
                2. It allows us to define if a panel's page transitions should be tracked in history
                or not.</p>
            <p style="padding-left: 30px;">
                This uses the data-hash attribute on the panels. It takes three options - 'true','false',
                and 'crumbs' with true as default. The 'crumbs' setting changes the panel's back
                button into a button that points to the previous page, and disables jQMobile from
                tracking the panel's history
            </p>
            <p>
                3. It allows us to hide and show the panel depending on screen orientation, and
                unobtrusively disable it when the site is viewed on mobile browsers</p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 8th page -->
    <div data-role="page" id="orientation">
        <div data-role="header">
            <h1>
                Orientation and Resize</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                Very simply put, SplitView dynamically lays out the pages based on your tablet's
                (iPad, etc) orientation, as well as your desktop's screen size. Try it out, resize
                your browser, or turn your iPad to see it in portrait and landscape modes!</p>
            <p>
                NOTE: you may have to refresh the view if you scale the browser window down to a
                mobile size - less than 480px - Splitview determines upon page load if it should
                lay the pages out in splitview mode or mobile mode (the default jQmobile implementation)</p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 9th page -->
    <div data-role="page" id="scroll">
        <div data-role="header">
            <h1>
                Scrolling</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
            Splitview detects if your device is touch enabled or not. it will then implement
            the proper scrolling mechanism for your device. This is possible thanks to the jQuery
            Mobile team's experimental momentum scroll implementation, which the team promptly
            pointed us to. Thanks!
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <div data-role="page" id="context">
        <div data-role="header">
            <h1>
                Context Loading</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                When you navigate on to some menus on the 'menu' panel, you'll find that it is more
                intuitive for users that the main panel also transitions to a related page. This
                is what we call context page loading<p>
                    <p>
                        Splitview now supports this. you need to define a data-context attribute on the
                        panel with a value of the selector of the link you'd like the main page to transition
                        to. this link has to be inside the page that is transitioning into view in the menu
                        panel, and it has to reference the main panel using the data-panel attribute. Example:</p>
                    <p style="padding-left: 30px;">
                        <b>data-context="a#default"</b></p>
                    <p>
                        This will look for a link with id="default" on the newly transitioned page, and
                        trigger a click event on it, changing the main panel to that page (<b>NOTE:</b>
                        the link needs to refer to the main panel using the data-panel="main" attribute!)</p>
                    <p>
                        To see this in action, click on the demo button at the bottom of the menu panel
                        on the left</p>
                    <p>
                        Also, you can also define a data-context attribute on a page itself - this will
                        override any data-context attributes defined on the panels</p>
                    <p>
                        There are still a few things i need to do to make sense of context for both pages,
                        e.g. when hitting back on history, what happens etc, but they will have to wait
                        for now :)</p>
                    <p>
                        <b>ANOTHER NOTE:</b> To make this happen, I made some small changes to the changePage
                        method in jQMobile core. use the version of jQuerymobile found in the experiments/compiled/
                        folder of my fork. It will not break any changePage calls you've made on your own
                        js code</p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 10th page -->
    <div data-role="page" id="page3">
        <div data-role="header">
            <h1>
                Page 3</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                Vestibulum porta pretium nunc, at adipiscing tortor fringilla sit amet. Sed venenatis
                varius turpis, vel fringilla purus egestas in. Curabitur interdum mauris nec velit
                vehicula sed aliquam nulla convallis. Nulla id magna libero, sagittis fringilla
                metus. Suspendisse dapibus tincidunt tristique. Fusce interdum tincidunt tincidunt.
                Phasellus tempus fringilla augue eget tincidunt. Donec facilisis mauris ut metus
                eleifend eget scelerisque nulla sagittis. Ut vel elit non risus dapibus luctus.
                Pellentesque vel nibh tortor.</p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <div data-role="page" id="page4">
        <div data-role="header">
            <h1>
                Page 4</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                Fusce a nisi at dolor rutrum tristique. Donec faucibus metus vitae lorem scelerisque
                malesuada scelerisque enim imperdiet. Aliquam in erat orci. Ut ultrices, erat eu
                luctus accumsan, lorem nibh cursus purus, in laoreet nisi tellus interdum sem. Nulla
                fringilla molestie lectus nec hendrerit. In in mollis tortor. Nunc lectus tortor,
                porttitor vitae viverra non, dignissim ac ligula. In tincidunt libero id turpis
                gravida iaculis rhoncus dolor aliquam. Vestibulum congue massa nec nibh sagittis
                tempor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames
                ac turpis egestas. Quisque quis urna arcu. Quisque feugiat ante id turpis ultrices
                vel imperdiet ipsum volutpat. Donec enim magna, pretium eu scelerisque ut, pretium
                placerat risus.</p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 3rd page -->
    <div data-role="page" id="bar">
        <div data-role="header">
            <h1>
                Bar</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                I'm first in the source order so I'm shown as the page.</p>
            <p>
                <a href="#badz">Back to badz</a></p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
    <!-- Start of 4th page -->
    <div data-role="page" id="badz">
        <div data-role="header">
            <h1>
                badz</h1>
        </div>
        <!-- /header -->
        <div data-role="content">
            <p>
                I'm first in the source order so I'm shown as the page.</p>
            <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque consectetur,
                ligula quis convallis gravida, tortor odio mattis purus, a fringilla mauris velit
                eu nisi. Vivamus laoreet tincidunt diam, sit amet tristique purus lobortis ac. Etiam
                commodo placerat elit. In aliquam dapibus felis, molestie molestie purus scelerisque
                sit amet. Donec vitae varius arcu. Aliquam dapibus dolor magna, nec posuere felis.
                Nullam in suscipit massa. Duis nec nulla nec urna sollicitudin fringilla. Proin
                at rutrum mi. Maecenas vitae urna ante, ac gravida tortor.</p>
            <p>
                Vestibulum porta pretium nunc, at adipiscing tortor fringilla sit amet. Sed venenatis
                varius turpis, vel fringilla purus egestas in. Curabitur interdum mauris nec velit
                vehicula sed aliquam nulla convallis. Nulla id magna libero, sagittis fringilla
                metus. Suspendisse dapibus tincidunt tristique. Fusce interdum tincidunt tincidunt.
                Phasellus tempus fringilla augue eget tincidunt. Donec facilisis mauris ut metus
                eleifend eget scelerisque nulla sagittis. Ut vel elit non risus dapibus luctus.
                Pellentesque vel nibh tortor.</p>
            <p>
                Fusce a nisi at dolor rutrum tristique. Donec faucibus metus vitae lorem scelerisque
                malesuada scelerisque enim imperdiet. Aliquam in erat orci. Ut ultrices, erat eu
                luctus accumsan, lorem nibh cursus purus, in laoreet nisi tellus interdum sem. Nulla
                fringilla molestie lectus nec hendrerit. In in mollis tortor. Nunc lectus tortor,
                porttitor vitae viverra non, dignissim ac ligula. In tincidunt libero id turpis
                gravida iaculis rhoncus dolor aliquam. Vestibulum congue massa nec nibh sagittis
                tempor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames
                ac turpis egestas. Quisque quis urna arcu. Quisque feugiat ante id turpis ultrices
                vel imperdiet ipsum volutpat. Donec enim magna, pretium eu scelerisque ut, pretium
                placerat risus.</p>
            Sed sed lacinia ante. Aenean non quam in ipsum pharetra condimentum.
            <p>
                Donec turpis lacus, pharetra ac viverra sit amet, lobortis eu nisl. Cum sociis natoque
                penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur porttitor
                dignissim orci ut feugiat. Praesent quis auctor purus. Suspendisse non elit accumsan
                mi pellentesque laoreet. Nullam et sapien sed nibh dictum tempor sit amet ut velit.
                Vestibulum varius ultricies lorem sed ultricies. Vestibulum auctor velit vitae ante
                eleifend eget bibendum metus rutrum. Nulla facilisis luctus mi laoreet rutrum. Nunc
                accumsan urna at elit pellentesque ut venenatis lectus adipiscing. Ut et arcu urna.
                Aliquam eros leo, ultricies vel porta nec, tempor sit amet leo. Quisque imperdiet
                facilisis orci ut malesuada. Nunc eget elit mauris. Mauris sed felis lectus.</p>
            <p>
                Duis purus sem, condimentum eget posuere sed, vulputate non lorem. Cum sociis natoque
                penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras risus urna,
                commodo quis interdum sit amet, elementum vitae lacus. Ut tempor hendrerit ante
                et facilisis. Vivamus elementum purus justo, ut auctor arcu. Cras varius rhoncus
                venenatis. Nulla dignissim velit a erat euismod pretium. In sed leo orci, et consectetur
                justo. Vestibulum ipsum urna, cursus in placerat in, malesuada eu odio. Nunc eget
                ullamcorper tortor. In commodo, turpis sed egestas egestas, dolor sem mattis nulla,
                eu semper lectus metus at eros. Sed cursus nisl id risus fermentum quis aliquam
                odio pretium. Quisque justo eros, blandit gravida tristique eget, rhoncus in magna.
                Integer volutpat faucibus dolor, sit amet tempor metus ornare consequat. Pellentesque
                habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
                Nunc et lacus enim, sit amet consequat turpis.</p>
            <p>
                <a href="#foo">Back to foo</a></p>
        </div>
        <!-- /content -->
        <div data-role="footer" data-position="fixed" data-id="ew-footer" class="ui-splitview-hidden">
            <div data-role="navbar">
                <ul>
                    <li><a href="#main" class="ui-btn-active" data-transition="slideup">Main</a></li>
                    <li><a href="#demo" data-transition="slideup">Demos</a></li>
                </ul>
            </div>
            <!-- /navbar -->
        </div>
        <!-- /footer -->
    </div>
    <!-- /page -->
</div>
<!-- panel main -->

Conclusion

We are done! This is just a simple dashboard prototype for a mobile website. If you view the site with a computer, you will be served the Home/Index view for regular website browsing. For mobile devices, you will be automatically routed to the Mobile controller which will further detect what mobile device you are using. The controller will service Tablet view for the iPad and all other mobile devices will be served the Index view.

Desktop Browsing


Mobile Browsing


Tablet Browsing


Check It Out for Yourself!

HAPPY CODING!!

More Reading:

comments powered by Disqus