www.twitter.com/Telerik www.facebook.com/Telerik
Philip Japikse (@skimedic) [email protected] www.skimedic.com/blog MVP, MCSD.Net, MCDBA, CSM, CSP
A LAP AROUND WINJS WINDOWS STORE APPLICATIONS
FOR THE WEB DEVELOPER – PART 2
PHIL.TOSTRING()
•
Evangelism Lead - DevTools, Telerik, Inc.
•
Microsoft MVP, MCSD, MCDBA, CSM, CSP
•
Lead Director, Cincinnati .NET User’s Group
•
Co-host Hallway Conversations Podcast
•
www.hallwayconversations.com
•
Founder, Agile Conferences, Inc.
APPLICATION STATES
•
Activated (onactivated)
•
Launched (ActivationKind.launch)
•
Search (ActivationKind.search)
•
SendTo (ActivationKind.shareTarget)
•
Suspended (oncheckpoint)
•
ApplicationExecutionState.suspended
•
Resumed (onactivated)
•
previousExecutionState.suspended
•
Terminated
ACTIVATION
app.onactivated =
function
(args) {
switch
(args.detail.kind) {
case
activation.ActivationKind.launch:
if
(args.detail.previousExecutionState !==
activation.ApplicationExecutionState.terminated) {
}
else
{
}
processPage(args);
break
;
}
};
SEARCH ACTIVATION
app.onactivated = function (args) {
switch (args.detail.kind) { case activation.ActivationKind.search: searchTerm = args.detail.queryText; if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.suspended) { JSONHandler.getContacts(); processPage(args); } WinJS.Navigation.navigate("pages/search/search.html", { searchTerm: searchTerm }); break; } };
SUSPENSION
app.oncheckpoint =
function
(args) {
app.sessionState.history = WinJS.Navigation.history;
app.sessionState.location = WinJS.Navigation.location;
args.setPromise(JSONHandler.saveContacts());
};
---saveContacts:
function
() {
return new
WinJS.Promise(
function
(fDone, fError, fProgress) {
//Save contacts
});
}
SESSION STATE
app.onactivated =
function
(args) {
//removed for brevity
if
(app.sessionState.history) {
WinJS.Navigation.history = app.sessionState.history;
}
if
(app.sessionState.location) {
WinJS.Navigation.navigate(app.sessionState.location);
}
}
ADDING SEARCH
•
Add Search Declaration in package.appmanifest
•
Handle Search activation in app.onactivated
HANDLING SEARCH ACTIVATION
app.onactivated =
function
(args) {
switch
(args.detail.kind) {
case
activation.ActivationKind.search:
searchTerm = args.detail.queryText;
if
(args.detail.previousExecutionState !==
activation.ApplicationExecutionState.suspended) {
// Restore application state
args.setPromise(WinJS.UI.processAll());
}
WinJS.Navigation.navigate("pages/search/search.html",
{ searchTerm: searchTerm });
break
;
};
PASS SEARCH TERM TO RESULTS PAGE
WinJS.UI.Pages.define("pages/search/search.html", {
ready: function
(element, data) {
ViewModel.searchContacts(data.searchTerm);
}
});
searchContacts: function
(searchTerm) {
SearchResults.contactList =
ContactData.contactList.createFiltered(function
(c) {
return
c.lastName.toLowerCase()
.indexOf(searchTerm.toLowerCase()) !== -1;
})
}
ADDING SHARE SOURCE
•
(Optional) Get Deferral
•
Add eventlistener to “datarequested” event
•
Populate the request object
•
Data
•
Properties (title, description, applicationName)
•
Set value
•
setText
SETTING UP SHARING
listView.addEventListener('selectionchanged',
function
(e) {
if
(
this
.winControl.selection.count() != 0) {
listView.selection.getItems().then(
function
(items) {
Contacts.Sharing.itemToShare = currentItem;
});
Contacts.Sharing.startSharing();
}
else
{
Contacts.Sharing.stopSharing();
}
});
STARTING/STOPPING SHARING
var
share = Windows.ApplicationModel.DataTransfer;
var
shareMgr = share.DataTransferManager;
WinJS.Namespace.define("Contacts.Sharing", {
itemToShare:
null
,
startSharing:
function
() {
shareMgr.getForCurrentView().addEventListener("datarequested",
Contacts.Sharing.shareHandler);
},
stopSharing:
function
() {
shareMgr.getForCurrentView().removeEventListener("datarequested",
Contacts.Sharing.shareHandler);
},
});
SHARE
WinJS.Namespace.define("Contacts.Sharing", {
shareHandler: function (e) {
var deferral = e.request.getDeferral();
var request = e.request;
var item = Contacts.Sharing.itemToShare;
request.data.properties.title = "Contact Information";
request.data.properties.description = "Contact Record for " + item.lastName; request.data.properties.applicationName = "WinJS Samples";
request.data.setHtmlFormat(
share.HtmlFormatHelper.createHtmlFormat(
"First Name:" + item.firstName + "<br/>"
+ "Last Name:" + item.lastName + "<br/>" + "Age:" + item.age)); deferral.complete();
}, });
ADDING SETTINGS
•
Create Settings Flyout
•
Add to Settings Charm
•
Read/Write Settings Data
•
Local Storage
•
Roaming Storage
•
<Optional> HighPriority
CREATING SETTINGS FLYOUT
<div id="colorsDiv" data-win-control="WinJS.UI.SettingsFlyout"
data-win-options="{width:narrow}"> <div class="win-header">
<button id="backbutton" class="win-backbutton"></button> <div class="win-label">Colors</div>
</div>
<div class="win-content"> <div>
<h2>Background Color</h2>
<input id="backgroundColorInput" data-win-bind="value:backgroundColor" /> </div>
<div>
<h2>Text Color</h2>
<input id="textColorInput" data-win-bind="value:textColor" /> </div>
<button id="saveColorsButton">Save</button> </div>
RESPONDING TO REQUEST FOR SETTINGS
app.onsettings =
function
(e) {
e.detail.applicationcommands = {
"colorsDiv":
{href:"pages/settings/colorsettings.html", title:"Colors"}
};
WinJS.UI.SettingsFlyout.populateSettings(e);
};
READ/WRITE SETTINGS
(function () { "use strict";
WinJS.UI.Pages.define("/pages/settings/colorsettings.html", {
ready: function(element) {
$('#colorsDiv input').listen('change', function(e) {
ApplicationState.Settings.backgroundColor = backgroundColorInput.value;
ApplicationState.Settings.textColor = textColorInput.value;
});
backbutton.addEventListener('click', function(e) {
WinJS.UI.SettingsFlyout.show(); });
WinJS.Binding.processAll(colorsDiv, ApplicationState.Settings); },
PERSISTING APPLICATION SETTINGS
var storage = Windows.Storage;
storage.ApplicationData.current.localSettings.values[setting] = newVal;
//Using Roaming Settings
storage.ApplicationData.current.roamingSettings.values[setting] = newVal;
//Listening for Changes to Roaming Settings
storage.ApplicationData.current.addEventListener("datachanged", function(e) {
loadSettings(); });
//Increasing the priority of a setting
PERSISTING COMPLEX VALUES
var
storage = Windows.Storage;
var
settings =
storage.ApplicationData.current.roamingSettings;
WinJS.Namespace.define("ApplicationState", {
compositeContainer: new
Windows.Storage.ApplicationDataCompositeValue(),
});
ApplicationState.compositeContainer.insert(setting, newVal);
settings.values["HighPriority"] =
ApplicationState.compositeContainer;
XML HTTP REQUESTS
•
WinJS.xhr(options).done(/* success & error handlers */)
•
type – GET(default) / HEAD / POST
•
url (required)
•
user/password
•
responseType
•
text (default), arrayBuffer, document (xml), json, plus more
•
headers
JSON
•
JSON.parse(text [,reviver])
PARSING JSON
var
items = JSON.parse(contactJSON);
items.forEach(
function
(item) {
ViewModel.addContact(
item.firstName, item.lastName, item.age, item.address);
});
---var
items = JSON.parse(contactJSON, dateReviver);
function
dateReviver(key, value) {
/* do something meaningful */
return
updatedValue
RENDERING JSON
var memberfilter = new Array();
memberfilter[0] = "firstName"; memberfilter[1] = "lastName"; memberfilter[2] = "age";
var contacts = JSON.stringify(
contactList.slice(0), memberfilter);
---var contacts = JSON.stringify(contactList.map(convertContacts));
convertContacts: function (contact) {
var simpleContact = returnSimpleContactInfo(contact);
if (contact.address) {
simpleContact.address = returnSimpleAddressInfo(contact.address); }
return simpleContact; }
CREATING A BADGE
•
Create Badge Type
•
Get and Update Badge XML
•
Create BadgeNotification
•
Update Badge with
CREATING A BADGE
createBadge: function (value) {
var badgeType = notify.BadgeTemplateType.badgeNumber;
var badgeXml = notify.BadgeUpdateManager.getTemplateContent(badgeType);
//"<badge value=\"\"/>"
badgeXml.getElementsByTagName("badge")[0].setAttribute("value", value);
var badgeNotification = new notify.BadgeNotification(badgeXml);
notify.BadgeUpdateManager.createBadgeUpdaterForApplication().update(badgeNot ification);
},
---addContact: function (firstName, lastName, age, address) {
//Omitted for brevity
Badges.createBadge(Model.ContactList.length);
return newContact; },
PINNING A TILE
pinTile: function (contact) {
var uri = new Windows.Foundation.Uri(
"ms-appx:///images/ConfBuddy_small.png");
var start = Windows.UI.StartScreen;
var tile = new start.SecondaryTile(
contact.lastName, // Tile ID
contact.lastName + " (" + contact.age + ")", // short name
contact.lastName + ", " + contact.firstName, //display name
JSON.stringify(returnSimpleContactInfo(contact)), // Activation argument
start.TileOptions.showNameOnLogo, // Tile options
uri // Tile logo URI
);
tile.requestCreateAsync(); },
RESPONDING TO PINNED TILE LAUNCHES
app.onactivated = function (args) {
switch (args.detail.kind) { case activation.ActivationKind.launch: if (args.detail.arguments !== "") { // Reconstitute Contact WinJS.Navigation.navigate("pages/contact/contact.html", { contact: item }); return; }
//Omitted for brevity
} }
CREATING A LIVE TILE
•
Create Square and Wide Tile XML
•
Choose Tile Template
•
Get and Update Tile XML
•
Merge both into 1 XML Doc
•
Create TileNotification
•
Update Tile with TileNotificationManager
CREATING TOAST
•
Create Toast Template
•
Get and Update Toast XML
•
Optional:
•
Set duration
•
Set Audio
•
Create ToastNotification with ToastNotificationManager
CREATING TOAST
function (title,line1, param) {
var template = notify.ToastTemplateType.toastText02;
var toastXml =
notify.ToastNotificationManager.getTemplateContent(template);
var toastTextElements = toastXml.getElementsByTagName("text");
toastTextElements[0].appendChild(toastXml.createTextNode(title)); toastTextElements[1].appendChild(toastXml.createTextNode(line1)); toastXml.selectSingleNode("/toast").setAttribute("launch", param);
var toast = new notify.ToastNotification(toastXml);
var toastNotifier = notify.ToastNotificationManager.createToastNotifier();
toastNotifier.show(toast); }