Skip to content
oazabir edited this page Jul 14, 2012 · 5 revisions

Main parts

There are three main parts in Droptiles:

  • Dashboard
  • App Store
  • Login, Signup, Settings.

Dashboard is the home page, that shows the tiles.

App Store shows a collection of apps available for users to add on the Dashboard.

Login, Signup, Settings areas are built using ASP.NET and uses ASP.NET Membership provider.

The Dashboard

Dashboard

Dashboard comprises of Sections. Each section contanis a collection of tiles. Each box you see are Tiles. Tiles are mini apps. A tile can be of the following type:

  • Simple html pages
  • A dynamic Javascript mini-App
  • Dynamic page

Coding a Tile

Let's look at the Flickr tile. First of all, all the tiles appearance are defined in the Tiles.js file, which contains the meta data for all the tiles. For example, the Flickr tile metadata is defined as following:

flickr: function (uniqueId) {
    return {
        uniqueId: uniqueId,
        name: "flickr",
        iconSrc: "img/Flickr alt 1.png",
        label: "Flickr",
        size: "tile-double tile-double-vertical",
        color: "bg-color-darken",
        appUrl: "http://www.flickr.com/",
        cssSrc: ["tiles/flickr/flickr.css"],
        scriptSrc: ["tiles/flickr/flickr.js"],
        initFunc: "flickr_load"
    };
}

Then icon is the default icon shown on the tile while the javascript, css, html are loaded. The horizontal and vertical size of the tile is defined in the size attribute. Then when clicked, what URL to host in the full screen view is defined in appUrl. The additional CSS, Javascripts to load are defined in cssSrc and scriptSrc. Finally the initFunc tells what function to invoke once the javascripts are loaded.

The metadat defines how the tile is displayed on the Dashboard. The behavior to load data from Flickr comes from the Flickr.js file, defined as follows:

function flickr_load(tile, div) {

	var url = "http://api.flickr.com/services/feeds/photos_public.gne?lang=en-us&format=json&tags=nature&jsoncallback=?";    

    $.getJSON(url, function (data) {        
        var ctr = 0;
        $.each(data.items.reverse(), function (i, item) {
            if (item.tags.length < 150) {
                var sourceSquare = item.media.m;
                var sourceOrig = (item.media.m).replace("_m.jpg", ".jpg");

                var htmlString = '<div class="flickr_item"> <a target="_blank" href="' + sourceOrig +
                    '" class="link" title="' + item.title + '">';
                htmlString += '<img title="' + item.title +
                    '" src="' + sourceSquare + '" ';
                htmlString += 'alt="' + item.title +
                    '" />';
                htmlString += '</a><div class="flickr_title">' + item.title + '</div>' +
                    '</div>';

                tile.slides.push(htmlString);

                ctr = ctr + 1;
            }
        });

        tile.counter(ctr);
    });
    
}

That's it.

The way Dashboard works is:

  • First get the list of Sections and the tiles in each section.
  • Create Tile boxes as per the definition stored in Tiles.js file.
  • For each Tile, see if the Tile has any external Javascript, CSS and html files to load. If yes, then load them.
  • Execute the function defined in the initFunc. Pass the tile object, the Tile div reference and the initParams to it.

Default tiles to show on Dashboard

The default tiles shown on Dashboard are defined in the same Tiles.js file as following:

window.DefaultTiles = [
    {
        name :"Section1",
        tiles: [
           { id: "flickr1", name:"flickr" },
           { id: "amazon1", name:"amazon" },
           { id: "news1", name: "news" },
           { id: "weather1", name: "weather" },
           { id: "calendar1", name: "calendar" },
           { id: "feature1", name: "feature" },
           { id: "facebook1", name: "facebook" }
        ]
    },
    {
        name: "Section2",
        tiles: [
           { id: "wikipedia1", name: "wikipedia" },           
           { id: "email1", name: "email" },
           { id: "maps1", name: "maps" },
           { id: "angrybirds1", name: "angrybirds" },
           { id: "cuttherope1", name: "cutTheRope" },
           { id: "dynamicTile1", name: "dynamicTile" },
           { id: "buy1", name: "buy" }]
    },
    {
        name: "Section3", tiles: [
           { id: "youtube1", name: "youtube" },
           { id: "ie1", name: "ie" },

        ]
    }
];

Tiles are shown in the exact order they are fined. The name has to be the same name used to define the Tile metadata.

HTML markup for tiles

There are various parts of a tile:

Tile parts

The following HTML defines the tile design:

<div class="metro-sections" data-bind="foreach: sections">
    <div class="metro-section" data-bind="attr: {id : uniqueId}, foreach: sortedTiles">
        <div data-bind="attr: { id: uniqueId, 'class': tileClasses }">
            <!-- ko if: tileImage -->
            <div class="tile-image">
                <img data-bind="attr: { src: tileImage }" src="img/Internet%20Explorer.png" />
            </div>
            <!-- /ko -->
            <!-- ko if: iconSrc -->
            <!-- ko if: slides().length == 0 -->
            <div data-bind="attr: { 'class': iconClasses }">
                <img data-bind="attr: { src: iconSrc }" src="img/Internet%20Explorer.png" />
            </div>
            <!-- /ko -->
            <!-- /ko -->
            <div data-bind="foreach: slides">
                <div class="tile-content-main">
                    <div data-bind="html: $data">
                    </div>
                </div>
            </div>
            <!-- ko if: label -->
            <span class="tile-label" data-bind="html: label">Label</span>
            <!-- /ko -->
            <!-- ko if: counter -->
            <span class="tile-counter" data-bind="html: counter">10</span>
            <!-- /ko -->
            <!-- ko if: subContent -->
            <div data-bind="attr: { 'class': subContentClasses }, html: subContent">
                subContent
            </div>
            <!-- /ko -->
        </div>
    </div>
</div>

The markup is full of KnockoutJS markups which is used to bind the Tile object model to the html markup.

Dashboard Execution

Here's a sequence diagram that shows how the Dashboard loads:

Sequence Diagram

The code in Dashboard.js starts like this:

var viewModel = new DashboardModel("Start", [], window.currentUser, ui, TileBuilders);

$(document).ready(function () {

    // Hide the body area until it is fully loaded in order to prevent flickrs
    $('#content').css('visibility', 'visible');

    // Initiate KnockoutJS binding which creates all the tiles and binds the whole
    // UI to viewModel.
    ko.applyBindings(viewModel);

    // See if user has a previous session where page setup was stored
    var cookie = readCookie("p");
    if (cookie != null && cookie.length > 0) {
        try {
            viewModel.loadSectionsFromString(cookie);
        } catch (e) {
            // Failed to load saved tiles. Load the default tiles.
            viewModel.loadSectionsFromString(DefaultTiles);
        }
    }
    else {
        // No cookie, load default tiles. Defined in Tiles.js
        viewModel.loadSectionsFromString(DefaultTiles);
    }

First it tries to read the section and tiles setup from the cookie, if it is saved. If not found in cookie, it loads the default definition.

The code is heavily documented, so you can read the details from there.

App Store

The App Store experience is built the same way as the Dashboard. The App Store shows how reusable the Droptiles framework is. It uses the same TheCore.js to provide the experience. All it does different is instead of Tiles.js which defines the tile metadata and the default tiles, it has its own AppStoreTiles.js that defines the Tile metadata and the default tiles to show on the App Store. That's all that differs.

Here's the code in AppStore.js:

var viewModel = new DashboardModel("App Store", [], window.currentUser, ui, TileBuilders);

$(document).ready(function () {

    // Hide the body area until it is fully loaded in order to prevent flickrs
    $('#content').css('visibility', 'visible');

    // Initiate KnockoutJS binding which creates all the tiles and binds the whole
    // UI to viewModel.
    ko.applyBindings(viewModel);

    viewModel.switchTheme('theme-white');
    viewModel.loadSectionsFromString(window.AppStoreTiles);

That's it. The loadSectionsFromString function takes care of creating the AppStore Tiles. It takes the section and tile configuration in a string serialized format, like this:

Section1~flickr1,flickr.news1,news|Section2~angrybirds1,angrybirds

This is how it is stored in the cookie as well so that next time you visit the Dashboard, it shows you how you have left it.