Today, the chief proposes you to delight yourself with the following dishes:
- Internationalization
- Managing the activation of the offline mode
- Adding a flipView to the cards page
- Handling snapped views
- Supporting different form factors
- Supporting different cards sizes

As usual the complete solution is there : http://www.catuhe.com/msdn/urza/day2.zip
The complete series can be found here:
- Day 0: http://blogs.msdn.com/b/eternalcoding/archive/2012/04/16/how-to-cook-a-complete-windows-8-application-with-html5-css3-and-javascript-in-a-week-day-0.aspx (First steps and project creation)
- Day 1: how-to-cook-a-complete-windows-8-application-with-html5-css3-and-javascript-in-a-week-day-1.aspx (Internationalization, Managing the activation of the offline mode , Adding a flipView to the cards page , Handling snapped views , Supporting different form factors , Supporting different cards sizes)
- Day 2: http://blogs.msdn.com/b/eternalcoding/archive/2012/04/23/how-to-cook-a-complete-windows-8-application-with-html5-css3-and-javascript-in-a-week-day-2.aspx (Internationalization , FliipView, snapped mode, resolution scalability)
- Day 3: http://blogs.msdn.com/b/eternalcoding/archive/2012/04/30/how-to-cook-a-complete-windows-8-application-with-html5-css3-and-javascript-in-a-week-day-3.aspx (Search contract, share contract, FilePicking contract, live tiles, secondary tiles)
- Day 4: http://blogs.msdn.com/b/eternalcoding/archive/2012/05/21/how-to-cook-a-complete-windows-8-application-with-html5-css3-and-javascript-in-a-week-day-4.aspx (Collection handling, Live SDK)
- Day 5: http://blogs.msdn.com/b/eternalcoding/archive/2012/06/15/how-to-cook-a-complete-windows-8-application-with-html5-css3-and-javascript-in-a-week-day-5.aspx (RP version)
- RTM version: http://blogs.msdn.com/b/eternalcoding/archive/2012/08/20/how-to-cook-a-windows-8-application-with-html5-javascrip-css3-rtm-version.aspx
Internationalization
UrzaGatherer is intended to be present on all marketplaces supported by the Windows 8 store. It is then important to internationalize it. To do so, you just have to add resources.resjon files in a folder named with the language you want to support (for instance, “en” for English or “fr” for French):


This file contains a json description of key/value pairs used by the localization system of WinJS (the core JavaScript of Windows 8 Metro):
{
"Settings" : "Settings",
"CardsZoomLevel" : "Cards zoom level",
"OfflineFiles" : "Offline files",
"OfflineFilesRestart" : "(You must restart to apply this settings)",
"On" : "On",
"Off" : "Off",
"DownloadInProgress" : " download(s) in progress",
"LoadingData" : "Loading data...please wait",
"ErrorConnection" : "Error during connection to server. Please check you connectivity.",
"All" : "All ",
"Colors" : "colors",
"Authors" : "authors",
"Rarities" : "rarities",
"Types" : "types",
"Cards" : " cards",
"Number" : "Number:",
"Type" : "Type:",
"Color" : "Color:",
"Power" : "Power:",
"Rarity" : "Rarity:",
"Text" : "Text:",
"Flavor" : "Flavor:",
"Author" : "Author:",
"AveragePrice" : "Average price:",
"ByNumber" : "By number",
"ByName" : "By name",
"OnlyMissing" : "Only missing",
"AllExceptMissing" : "All except missing"
}
You can have this kind of file for each language you want to support. WinJS will then choose for you the right file according to the active user language.
To use the resource file in your HTML page, you have to add a data-win-res attribute:
<span data-win-res="{innerText: 'OfflineFilesRestart'}"></span>
Calling the following function will process the added attribute and will affect the resource string to the specified property:
WinJS.Resources.processAll();
You just have to not forget to call it. For UrzaGatherer I call it in the ready function of my pages:
ui.Pages.define("/pages/card/card.html", {
ready: function (element, options) {
WinJS.Resources.processAll();
Furthermore, you can also call the resource system from your own code to get the value associated to a given key:
var resourceLoader = new Windows.ApplicationModel.Resources.ResourceLoader();
var getString = function (name) {
if (!name)
return "";
return resourceLoader.getString(name);
};
Managing the activation of the offline mode
Some users may not want to use the offline files mode (to prevent UrzaGatherer to use too much disk space for instance). To handle that, you can add a new property in the settings:

To do so, you just have to add the following HTML code in the default.html page:
<div id="settingsDiv" data-win-control="WinJS.UI.SettingsFlyout" data-win-options="{width:'narrow'}">
<div class="win-header">
<button type="button" onclick="WinJS.UI.SettingsFlyout.show()" class="win-backbutton">
</button>
<div class="win-label" data-win-res="{innerText: 'Settings'}"></div>
</div>
<div class="win-content">
<h4 data-win-res="{innerText: 'CardsZoomLevel'}"></h4>
<input type="range" id="zoomRange" min="20" max="80" value="50" />
<fieldset class="controlGroup">
<legend class="controlGroupName"><span data-win-res="{innerText: 'OfflineFiles'}"></span>
<br />
<i><span data-win-res="{innerText: 'OfflineFilesRestart'}"></span></i>
</legend>
<label class="radioLabel horizontalLabelLayout">
<input type="radio" name="offlineMode" checked id="offlineModeOn"/>
<span data-win-res="{innerText: 'On'}"></span>
</label>
<label class="radioLabel horizontalLabelLayout">
<input type="radio" name="offlineMode" id="offlineModeOff"/>
<span data-win-res="{innerText: 'Off'}"></span>
</label>
</fieldset>
</div>
</div>
Each radio controls the state of the offlineMode roaming setting:
// Offline mode
var on = document.getElementById("offlineModeOn");
var off = document.getElementById("offlineModeOff");
var offlineMode = Windows.Storage.ApplicationData.current.roamingSettings.values["offlineMode"];
if (offlineMode)
on.checked = true;
else
off.checked = true;
on.addEventListener("change", function () {
Windows.Storage.ApplicationData.current.roamingSettings.values["offlineMode"] = true;
});
off.addEventListener("change", function () {
Windows.Storage.ApplicationData.current.roamingSettings.values["offlineMode"] = false;
});
The image loading code is then modified to switch between a local mode (ms-appdata) et un mode distant (http):
var offlineMode = Windows.Storage.ApplicationData.current.roamingSettings.values["offlineMode"];
if (offlineMode) {
block.logo = "ms-appdata:///local/blocks/" + block.name.replace(":", "_") + ".png";
block.banner = "ms-appdata:///local/blocks/" + block.name.replace(":", "_") + "_banner.png";
}
else {
block.logo = root + "/blocks/" + block.name.replace(":", "_") + ".png";
block.banner = root + "/blocks/" + block.name.replace(":", "_") + "_banner.png";
}
And voila!
.
Adding a flipView to the cards page
The next stop is for the card page which can be easily improved by adding a flipView control to switch between cards without having to go back to the expansion page.
The flipView is a touch aware control which allows you to slide between items but it also allows you to use your mouse with the navigation buttons on the left and right edges of the control:

By the way, the data have to be bound now and not directly set by code:
<body>
<!--Template-->
<div class="itemTemplate" data-win-control="WinJS.Binding.Template">
<div class="item-root">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back"></button>
<h1 class="titlearea win-type-ellipsis"><span class="pagetitle"
data-win-bind="innerText: name">
</span></h1>
</header>
<section aria-label="Main content" role="main">
<h3 class="item-number-label" data-win-res="{innerText: 'Number'}"></h3>
<div class="item-number" data-win-bind="innerText: number"></div>
<h3 class="item-type-label" data-win-res="{innerText: 'Type'}"></h3>
<div class="item-type" data-win-bind="innerText: type"></div>
<h3 class="item-color-label" data-win-res="{innerText: 'Color'}"></h3>
<div class="item-color" data-win-bind="innerText: color"></div>
<h3 class="item-power-label" data-win-res="{innerText: 'Power'}"></h3>
<div class="item-power" data-win-bind="innerText: power"></div>
<h3 class="item-rarity-label" data-win-res="{innerText: 'Rarity'}"></h3>
<div class="item-rarity" data-win-bind="innerText: rarity"></div>
<h3 class="item-text-label" data-win-res="{innerText: 'Text'}"></h3>
<div class="item-text" data-win-bind="innerText: text"></div>
<h3 class="item-flavor-label" data-win-res="{innerText: 'Flavor'}"></h3>
<div class="item-flavor" data-win-bind="innerText: flavor"></div>
<h3 class="item-author-label" data-win-res="{innerText: 'Author'}"></h3>
<div class="item-author" data-win-bind="innerText: author"></div>
<h3 class="item-price-label" data-win-res="{innerText: 'AveragePrice'}"></h3>
<div class="item-price" data-win-bind="innerText: price UrzaGatherer.Tools.PriceConverter">
</div>
<div class="item-image-container" data-win-control="UrzaGatherer.Tools.DelayImageLoader"
data-win-options="{root: 'cards'}">
<img class="item-image-container" data-win-bind="src: logo" />
</div>
<div class="expansion-image-container" data-win-control="UrzaGatherer.Tools.DelayImageLoader">
<img class="expansion-picture" src="#" data-win-bind="src: expansion.banner" />
</div>
</section>
</div>
</div>
<!--Content-->
<div class="card fragment">
<div id="flipView" data-win-control="WinJS.UI.FlipView"
data-win-options="{ itemTemplate : select('.itemTemplate') }">
</div>
</div>
</body>
You can notice the presence of data-win-res for the localization and the presence of data-win-bind for the binding.
To set up the connection between the flipView and the data, you can faily use the same code you used for the listView:
var flipView = document.getElementById("flipView").winControl;
ui.setOptions(flipView, {
itemDataSource: options.cards.dataSource,
currentPage: options.cardIndex
});
Handling snapped views
To be able to pass store certifications, your application must support the snapped view. This mode is activated when your application is set side by side with another application. The space allowed for a snapped application is 320px wide.
You have to define a new design for the snapped view for each screen of your application.
For UrzaGatherer, I decided to provide a complete experience when in snapped view. You can of course choose to remove non relevant features but for UrzaGatherer, all features are dispatched in the snapped view.
The main screen evolves like this:

The expansion screen in snapped view is like this:

And the card screen:

The magic thing here is that all these modifications are done using only one feature : the media queries (http://msdn.microsoft.com/en-us/library/windows/apps/hh453556.aspx). This feature allows you to select new CSS rules based on specific queries (for instance, the application is in snapped mode).
Here is an example for the expansion page:
@media screen and (-ms-view-state: snapped) {
#cardsCount {
display: none;
}
#cardsPrice {
display: none;
}
.expansion section[role=main] {
-ms-grid-rows: 0px 1fr;
}
}
These rules will replace (or complete) the original rules. For example, the base rules for “.expansion section[role=main]” is the following:
.expansion section[role=main] {
-ms-grid-columns: 1fr;
-ms-grid-rows: 50px 1fr;
display: -ms-grid;
}
In snapped mode, according to our media query it will become:
.expansion section[role=main] {
-ms-grid-columns: 1fr;
-ms-grid-rows: 0px 1fr;
display: -ms-grid;
}
Your job is then to use media queries to move your HTML elements from a large horizontal layout to a small vertical layout (thanks to CSS3 Grids!).
Supporting different form factors
Media queries can also be used to adapt your application to different form factors. For example, the card page can use a media query to adapt its display to small resolutions:
@media screen and (min-height: 1024px) {
.card section[role=main] {
-ms-grid-columns: auto 1fr 960px;
}
.card .item-image-container {
margin-top: 0px;
}
}
On a large resolution the display is like this:

And on a smaller resolution:

You can see that the columns are smaller and the picture is moved upwards to have enough room to display.
Supporting different cards sizes
The last point I want to talk today is about handling multi-templates for the listView. Indeed, some cards in my collection are twice wider than the standard ones (mainly in the Planechase expansion):

To do so, instead of giving a static template, you can provide a JavaScript function that builds dynamically the template:
var listView = element.querySelector(".cardsList").winControl;
ui.setOptions(listView, {
itemTemplate: this.itemRenderer,
oniteminvoked: this.itemInvoked.bind(this)
});
The itemRenderer function is responsible for rendering each item. So you have the full control on how every element is produced! In this case you can check if the card is large or not and accordingly you can modify the styles:
itemRenderer: function (itemPromise) {
return itemPromise.then(function (currentItem, recycled) {
var template = document.querySelector(".itemTemplate").winControl.renderItem(itemPromise, recycled);
template.renderComplete = template.renderComplete.then(function (elem) {
if (currentItem.data.isLarge) {
var zoomLevel = Windows.Storage.ApplicationData.current.roamingSettings.values["zoomLevel"];
if (!zoomLevel)
return;
var level = zoomLevel / 100.0;
elem.querySelector(".item-container").style.width = (480 * level * 2) + "px";
}
});
return template.element;
})
},
You can note that the code take the local zoom in account to compute the correct size.
However, it is not sufficient. Indeed, the listView must be in “multisize” mode to support different sizes items. To achieve this, it is necessary to add a “groupInfo” parameter:
ui.setOptions(listView, {
itemDataSource: filtered.dataSource,
layout: new ui.GridLayout({
groupHeaderPosition: "top",
groupInfo: function () {
var zoomLevel = Windows.Storage.ApplicationData.current.roamingSettings.values["zoomLevel"];
if (!zoomLevel)
zoomLevel = 50;
var level = zoomLevel / 100.0;
return {
multiSize: true,
slotWidth: Math.round(480 * level),
slotHeight: Math.round(680 * level)
};
}
})
});
It is clearly important to provide a correct cell size (slotWidth et slotHeight) because every item in the listView must have a size proportional to cell size !
To be continued
Our next stop will be focused on integrating with Windows 8:
- Search contract
- Share contract
- FileOpenPicker
- Live tiles
- Secondary tiles