Create a blog reader complete code
This topic provides the complete code sample used in the tutorial Create a blog reader.
This topic contains these sections:
- Technologies
- Requirements
- View the code (JavaScript)
Download location
This sample is not available for download.
Technologies
Programming languages | HTML, JavaScript |
Programming models | Windows Runtime |
Requirements
Minimum supported client | Windows 8 |
Minimum supported server | Windows Server 2012 |
Minimum required SDK | Microsoft Visual Studio Express 2012 for Windows 8 |
View the code (JavaScript)
data.js
(function () {
"use strict";
// Set up array variables
var dataPromises = [];
var blogs;
// Create a data binding for our ListView
var blogPosts = new WinJS.Binding.List();
// Process the blog feeds
function getFeeds() {
// Create an object for each feed in the blogs array
// Get the content for each feed in the blogs array
// Return when all asynchronous operations are complete
// Create an object for each feed in the blogs array
blogs = [
{
key: "blog1",
url: 'https://blogs.windows.com/windows/b/windowsexperience/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog2",
url: 'https://blogs.windows.com/windows/b/extremewindows/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog3",
url: 'https://blogs.windows.com/windows/b/business/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog4",
url: 'https://blogs.windows.com/windows/b/bloggingwindows/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog5",
url: 'https://blogs.windows.com/windows/b/windowssecurity/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog6",
url: 'https://blogs.windows.com/windows/b/springboard/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog7",
url: 'https://blogs.windows.com/windows/b/windowshomeserver/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog8",
url: 'https://blogs.windows.com/windows_live/b/developer/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog9",
url: 'https://blogs.windows.com/ie/b/ie/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog10",
url: 'https://blogs.windows.com/windows_phone/b/wpdev/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
},
{
key: "blog11",
url: 'https://blogs.windows.com/windows_phone/b/wmdev/atom.aspx',
title: 'tbd', updated: 'tbd',
acquireSyndication: acquireSyndication, dataPromise: null
}];
// Get the content for each feed in the blogs array
blogs.forEach(function (feed) {
feed.dataPromise = feed.acquireSyndication(feed.url);
dataPromises.push(feed.dataPromise);
});
// Return when all asynchronous operations are complete
return WinJS.Promise.join(dataPromises).then(function () {
return blogs;
});
}
function acquireSyndication(url) {
// Call xhr for the URL to get results asynchronously
return WinJS.xhr(
{
url: url,
headers: { "If-Modified-Since": "Mon, 27 Mar 1972 00:00:00 GMT" }
});
}
function getBlogPosts() {
// Walk the results to retrieve the blog posts
getFeeds().then(function () {
// Process each blog
blogs.forEach(function (feed) {
feed.dataPromise.then(function (articlesResponse) {
var articleSyndication = articlesResponse.responseXML;
if (articleSyndication) {
// Get the blog title
feed.title = articleSyndication.querySelector("feed > title").textContent;
// Use the date of the latest post as the last updated date
var published = articleSyndication.querySelector("feed > entry > published").textContent;
// Convert the date for display
var date = new Date(published);
var dateFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
"month.abbreviated day year.full");
var blogDate = dateFmt.format(date);
feed.updated = "Last updated " + blogDate;
// Get the blog posts
getItemsFromXml(articleSyndication, blogPosts, feed);
}
else {
// There was an error loading the blog.
feed.title = "Error loading blog";
feed.updated = "Error";
blogPosts.push({
group: feed,
key: "Error loading blog",
title: feed.url,
author: "Unknown",
month: "?",
day: "?",
year: "?",
content: "Unable to load the blog at " + feed.url
});
}
});
});
});
return blogPosts;
}
function getItemsFromXml(articleSyndication, bPosts, feed) {
// Get the info for each blog post
var posts = articleSyndication.querySelectorAll("entry");
// Process each blog post
for (var postIndex = 0; postIndex < posts.length; postIndex++) {
var post = posts[postIndex];
// Get the title, author, and date published
var postTitle = post.querySelector("title").textContent;
var postAuthor = post.querySelector("author > name").textContent;
var postPublished = post.querySelector("published").textContent;
// Convert the date for display
var postDate = new Date(postPublished);
var monthFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
"month.abbreviated");
var dayFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
"day");
var yearFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
"year.full");
var blogPostMonth = monthFmt.format(postDate);
var blogPostDay = dayFmt.format(postDate);
var blogPostYear = yearFmt.format(postDate);
// Process the content so it displays nicely
var staticContent = toStaticHTML(post.querySelector("content").textContent);
// Store the post info we care about in the array
bPosts.push({
group: feed,
key: feed.title,
title: postTitle,
author: postAuthor,
month: blogPostMonth.toUpperCase(),
day: blogPostDay,
year: blogPostYear,
content: staticContent
});
}
}
var list = getBlogPosts();
var groupedItems = list.createGrouped(
function groupKeySelector(item) { return item.group.key; },
function groupDataSelector(item) { return item.group; }
);
WinJS.Namespace.define("Data", {
items: groupedItems,
groups: groupedItems.groups,
getItemReference: getItemReference,
getItemsFromGroup: getItemsFromGroup,
resolveGroupReference: resolveGroupReference,
resolveItemReference: resolveItemReference
});
// Get a reference for an item, using the group key and item title as a
// unique reference to the item that can be easily serialized.
function getItemReference(item) {
return [item.group.key, item.title];
}
// This function returns a WinJS.Binding.List containing only the items
// that belong to the provided group.
function getItemsFromGroup(group) {
return list.createFiltered(function (item) { return item.group.key === group.key; });
}
// Get the unique group corresponding to the provided group key.
function resolveGroupReference(key) {
for (var i = 0; i < groupedItems.groups.length; i++) {
if (groupedItems.groups.getAt(i).key === key) {
return groupedItems.groups.getAt(i);
}
}
}
// Get a unique item from the provided string array, which should contain a
// group key and an item title.
function resolveItemReference(reference) {
for (var i = 0; i < groupedItems.length; i++) {
var item = groupedItems.getAt(i);
if (item.group.key === reference[0] && item.title === reference[1]) {
return item;
}
}
}
})();
default.css
#contenthost {
height: 100%;
width: 100%;
background-color: #0A2562;
}
.fragment {
/* Define a grid with rows for a banner and a body */
-ms-grid-columns: 1fr;
-ms-grid-rows: 128px 1fr;
display: -ms-grid;
height: 100%;
width: 100%;
}
.fragment header[role=banner] {
/* Define a grid with columns for the back button and page title. */
-ms-grid-columns: 120px 1fr;
-ms-grid-rows: 1fr;
display: -ms-grid;
}
.fragment header[role=banner] .win-backbutton {
margin-left: 39px;
margin-top: 59px;
}
.fragment header[role=banner] .titlearea {
-ms-grid-column: 2;
margin-top: 37px;
}
.fragment header[role=banner] .titlearea .pagetitle {
width: calc(100% - 20px);
}
.fragment section[role=main] {
-ms-grid-row: 2;
height: 100%;
width: 100%;
}
@media screen and (-ms-view-state: snapped) {
.fragment header[role=banner] {
-ms-grid-columns: auto 1fr;
margin-left: 20px;
}
.fragment header[role=banner] .win-backbutton {
margin: 0;
margin-right: 10px;
margin-top: 76px;
}
.fragment header[role=banner] .win-backbutton:disabled {
display: none;
}
.fragment header[role=banner] .titlearea {
-ms-grid-column: 2;
margin-left: 0;
margin-top: 68px;
}
}
@media screen and (-ms-view-state: fullscreen-portrait) {
.fragment header[role=banner] {
-ms-grid-columns: 100px 1fr;
}
.fragment header[role=banner] .win-backbutton {
margin-left: 29px;
}
}
default.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WindowsBlogReader</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- WindowsBlogReader references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/data.js"></script>
<script src="/js/default.js"></script>
<script src="/js/navigator.js"></script>
</head>
<body>
<div id="contenthost" data-win-control="Application.PageControlNavigator" data-win-options="{home: '/pages/items/items.html'}"></div>
<div id="appbar" data-win-control="WinJS.UI.AppBar">
<button data-win-control="WinJS.UI.AppBarCommand"
data-win-options="{id:'view', label:'Full View', icon:'add'}" type="button">
</button>
</div>
</body>
</html>
default.js
// For an introduction to the Split template, see the following documentation:
// https://go.microsoft.com/fwlink/p/?LinkID=232447
(function () {
"use strict";
WinJS.Binding.optimizeBindingReferences = true;
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var nav = WinJS.Navigation;
app.addEventListener("activated", function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
if (app.sessionState.history) {
nav.history = app.sessionState.history;
}
args.setPromise(WinJS.UI.processAll().then(function () {
if (nav.location) {
nav.history.current.initialPlaceholder = true;
return nav.navigate(nav.location, nav.state);
} else {
return nav.navigate(Application.navigator.home);
}
}));
}
});
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. If you need to
// complete an asynchronous operation before your application is
// suspended, call args.setPromise().
app.sessionState.history = nav.history;
};
app.start();
})();
itemDetail.css
.itemDetail section[role=main] {
-ms-grid-row: 2;
display: block;
height: 100%;
overflow-x: auto;
position: relative;
width: 100%;
z-index: 0;
}
.itemDetail section[role=main] article {
/* Define a multi-column, horizontally scrolling article by default. */
column-fill: auto;
column-gap: 80px;
column-width: 480px;
height: calc(100% - 50px);
margin-left: 120px;
width: 480px;
}
.itemDetail section[role=main] article .item-content p {
margin-bottom: 20px;
margin-right: 20px;
vertical-align: baseline;
}
@media screen and (-ms-view-state: snapped) {
.itemDetail section[role=main] article {
/* Define a single column, vertically scrolling article in snapped mode. */
-ms-grid-columns: 300px 1fr;
-ms-grid-row: 2;
-ms-grid-rows: auto 60px;
display: -ms-grid;
height: 100%;
margin-left: 20px;
overflow-x: hidden;
overflow-y: auto;
width: 300px;
}
.itemDetail section[role=main] article .item-content {
padding-bottom: 60px;
}
}
@media screen and (-ms-view-state: fullscreen-portrait) {
.itemDetail section[role=main] article {
margin-left: 100px;
}
}
itemDetail.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>itemDetail</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<link href="itemDetail.css" rel="stylesheet" />
<script src="itemDetail.js"></script>
</head>
<body>
<div class="itemDetail fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Welcome to itemDetail</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<article>
<div class="item-content"></div>
</article>
</section>
</div>
</body>
</html>
itemDetail.js
// For an introduction to the Page Control template, see the following documentation:
// https://go.microsoft.com/fwlink/p/?LinkID=232511
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/itemDetail/itemDetail.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
// Display the appbar but hide the Full View button
var appbar = document.getElementById('appbar');
var appbarCtrl = appbar.winControl;
appbarCtrl.hideCommands(["view"], false);
var item = options && options.item ? options.item : Data.items.getAt(0);
element.querySelector(".titlearea .pagetitle").textContent = item.title;
element.querySelector("article .item-content").innerHTML = item.content;
},
unload: function () {
// TODO: Respond to navigations away from this page.
},
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
// TODO: Respond to changes in viewState.
}
});
})();
items.css
.itemspage section[role=main] {
-ms-grid-row: 1;
-ms-grid-row-span: 2;
}
/* This selector is used to prevent ui-dark/light.css from overwriting changes
to .win-surface. */
.itemspage .itemslist .win-horizontal.win-viewport .win-surface {
margin-bottom: 60px;
margin-left: 115px;
margin-right: 115px;
margin-top: 155px;
}
.itemspage .itemslist {
height: 100%;
position: relative;
width: 100%;
z-index: 0;
}
.itemspage .itemslist .item {
-ms-grid-columns: 1fr;
-ms-grid-rows: 1fr 60px;
display: -ms-grid;
height: 250px;
width: 250px;
background-color: #557EB9;
}
.itemspage .itemslist .win-item .item-title {
-ms-grid-row: 1;
overflow: hidden;
width: 220px;
font-size: 24px;
margin-top: 12px;
margin-left: 15px;
}
.itemspage .itemslist .item .item-image {
-ms-grid-row-span: 2;
}
.itemspage .itemslist .item .item-overlay {
-ms-grid-row: 2;
-ms-grid-rows: 1fr 21px;
display: -ms-grid;
padding: 6px 15px 2px 15px;
}
.itemspage .itemslist .item .item-overlay .item-title {
-ms-grid-row: 1;
overflow: hidden;
width: 220px;
}
.itemspage .itemslist .item .item-overlay .item-subtitle {
-ms-grid-row: 2;
width: 220px;
}
@media screen and (-ms-view-state: fullscreen-landscape), screen and (-ms-view-state: fullscreen-portrait), screen and (-ms-view-state: filled) {
.itemspage .itemslist .item .item-overlay {
background: rgba(0,0,0,0.65);
}
.itemspage .itemslist .item .item-overlay .item-title {
color: rgba(255,255,255,0.87);
}
.itemspage .itemslist .item .item-overlay .item-subtitle {
color: rgba(255,255,255,0.6);
}
}
@media screen and (-ms-view-state: fullscreen-landscape) and (-ms-high-contrast), screen and (-ms-view-state: fullscreen-portrait) and (-ms-high-contrast), screen and (-ms-view-state: filled) and (-ms-high-contrast) {
.itemspage .itemslist .item .item-overlay {
color: WindowText;
}
}
@media screen and (-ms-view-state: snapped) {
.itemspage section[role=main] {
-ms-grid-row: 2;
-ms-grid-row-span: 1;
}
.itemspage .itemslist {
margin-top: 0;
}
.itemspage .itemslist .win-vertical.win-viewport .win-surface {
margin-bottom: 30px;
}
.itemspage .itemslist .win-container {
margin-bottom: 15px;
margin-left: 13px;
margin-right: 35px;
padding: 7px;
}
.itemspage .itemslist .item {
-ms-grid-columns: 60px 1fr;
-ms-grid-rows: 1fr;
display: -ms-grid;
height: 60px;
width: 272px;
}
.itemspage .itemslist .item .item-image, .itemspage .itemslist .item:hover .item-image {
-ms-grid-column: 1;
-ms-grid-row-span: 1;
height: 60px;
width: 60px;
}
.itemspage .itemslist .item .item-overlay {
-ms-grid-column: 2;
-ms-grid-row: 1;
-ms-grid-row-align: stretch;
background: transparent;
display: inline-block;
margin-left: 10px;
padding: 0;
}
.itemspage .itemslist .item .item-overlay .item-title {
margin-top: 4px;
max-height: 40px;
width: 202px;
}
.itemspage .itemslist .item .item-overlay .item-subtitle {
opacity: 0.6;
width: 202px;
}
}
@media screen and (-ms-view-state: fullscreen-portrait) {
.itemspage .itemslist .win-horizontal.win-viewport .win-surface {
margin-left: 100px;
}
}
items.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>itemsPage</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<link href="/css/default.css" rel="stylesheet" />
<link href="/pages/items/items.css" rel="stylesheet" />
<script src="/js/data.js"></script>
<script src="/pages/items/items.js"></script>
</head>
<body>
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
<div class="item">
<h4 class="item-title" data-win-bind="textContent: title"></h4>
<div class="item-overlay">
<h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: updated"></h6>
</div>
</div>
</div>
<!-- The content that will be loaded and displayed. -->
<div class="itemspage fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Windows Team Blogs</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<div class="itemslist win-selectionstylefilled" aria-label="List of groups" data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }"></div>
</section>
</div>
</body>
</html>
items.js
(function () {
"use strict";
var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
var ui = WinJS.UI;
ui.Pages.define("/pages/items/items.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
var listView = element.querySelector(".itemslist").winControl;
listView.itemDataSource = Data.groups.dataSource;
listView.itemTemplate = element.querySelector(".itemtemplate");
listView.oniteminvoked = this._itemInvoked.bind(this);
this._initializeLayout(listView, Windows.UI.ViewManagement.ApplicationView.value);
listView.element.focus();
// Display the appbar but hide the Full View button
var appbar = document.getElementById('appbar');
var appbarCtrl = appbar.winControl;
appbarCtrl.hideCommands(["view"], false);
},
// This function updates the page layout in response to viewState changes.
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
var listView = element.querySelector(".itemslist").winControl;
if (lastViewState !== viewState) {
if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
var handler = function (e) {
listView.removeEventListener("contentanimating", handler, false);
e.preventDefault();
}
listView.addEventListener("contentanimating", handler, false);
var firstVisible = listView.indexOfFirstVisible;
this._initializeLayout(listView, viewState);
if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
listView.indexOfFirstVisible = firstVisible;
}
}
}
},
// This function updates the ListView with new layouts
_initializeLayout: function (listView, viewState) {
/// <param name="listView" value="WinJS.UI.ListView.prototype" />
if (viewState === appViewState.snapped) {
listView.layout = new ui.ListLayout();
} else {
listView.layout = new ui.GridLayout();
}
},
_itemInvoked: function (args) {
var groupKey = Data.groups.getAt(args.detail.itemIndex).key;
WinJS.Navigation.navigate("/pages/split/split.html", { groupKey: groupKey });
}
});
})();
navigator.js
navigator.js contains only generated code.
split.css
.splitpage {
-ms-grid-columns: 640px 1fr;
display: -ms-grid;
height: 100%;
width: 100%;
}
.splitpage .itemlistsection .itemlist .item .item-date {
-ms-grid-column: 1;
background-color: #557EB9;
}
.splitpage .itemlistsection .itemlist .item .item-date .item-month{
margin-top: 12px;
margin-left: 12px;
margin-bottom: 4px;
font-weight: bold;
font-size: 28px;
}
.splitpage .itemlistsection .itemlist .item .item-date .item-day{
margin-left: 12px;
font-size: 28px;
}
.splitpage header[role=banner] .pagetitle {
-ms-grid-column: 2;
overflow: hidden;
width: calc(100% - 20px);
}
.splitpage .itemlistsection {
-ms-grid-row: 2;
margin-left: 106px;
}
.splitpage .itemlistsection .itemlist {
height: 100%;
position: relative;
width: 100%;
z-index: 0;
}
.splitpage .itemlistsection .itemlist .win-vertical.win-viewport .win-surface {
margin-bottom: 60px;
}
.splitpage .itemlistsection .itemlist .win-container {
margin-bottom: 15px;
margin-right: 35px;
padding: 7px;
}
.splitpage .itemlistsection .itemlist .win-container .win-selectioncheckmark, .splitpage .itemlistsection .itemlist .win-container .win-selectioncheckmarkbackground {
display: none;
}
.splitpage .itemlistsection .itemlist .item {
-ms-grid-columns: 110px 1fr;
-ms-grid-rows: 1fr;
display: -ms-grid;
height: 110px;
width: 500px;
}
.splitpage .itemlistsection .itemlist .item .item-info {
-ms-grid-column: 2;
margin-left: 10px;
margin-right: 10px;
overflow: hidden;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-title {
margin-top: 4px;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-subtitle {
opacity: 0.6;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-description {
max-height: 60px;
overflow: hidden;
}
.splitpage .articlesection {
-ms-grid-column: 2;
-ms-grid-row: 2;
-ms-grid-row-span: 2;
margin-left: 50px;
overflow-y: auto;
padding-right: 120px;
position: relative;
z-index: 0;
}
.splitpage .articlesection header {
-ms-grid-columns: 180px 20px 1fr;
-ms-grid-rows: 180px;
display: -ms-grid;
margin-bottom: 5px;
margin-top: 60px;
}
.splitpage .articlesection header .text {
-ms-grid-column: 3;
}
.splitpage .articlesection header .text .article-subtitle {
margin-top: 4px;
}
.splitpage .articlesection header .article-image {
height: 180px;
width: 180px;
}
.splitpage .articlesection .article-content {
overflow-y: auto;
}
.splitpage .articlesection .article-content p {
margin-bottom: 16pt;
}
@media screen and (-ms-view-state: filled) {
.splitpage {
-ms-grid-columns: 420px 1fr;
}
.splitpage .itemlistsection .itemlist .item {
-ms-grid-columns: 60px 1fr;
height: 60px;
margin-bottom: 0;
width: 282px;
}
.splitpage .itemlistsection .itemlist .item .item-image {
height: 60px;
width: 60px;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-title {
margin-top: 4px;
max-height: 40px;
overflow: hidden;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-description {
display: none;
}
.splitpage .articlesection {
margin-left: 60px;
padding-right: 66px;
}
}
@media screen and (-ms-view-state: snapped) {
.splitpage {
-ms-grid-columns: 320px 0px;
}
.splitpage .itemlistsection {
margin-left: 6px;
}
.splitpage .itemlistsection .itemlist .item {
-ms-grid-columns: 60px 1fr;
height: 60px;
width: 282px;
}
.splitpage .itemlistsection .itemlist .item .item-image {
height: 60px;
width: 60px;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-title {
margin-top: 4px;
max-height: 30pt;
overflow: hidden;
}
.splitpage .itemlistsection .itemlist .item .item-info .item-description {
visibility: hidden;
}
.splitpage .articlesection {
-ms-grid-row-span: 1;
-ms-grid-row: 2;
margin-left: 20px;
padding-right: 36px;
}
.splitpage .articlesection header {
display: block;
margin-top: 0;
}
.splitpage .articlesection header .text {
-ms-grid-column: 1;
margin-top: 6px;
}
.splitpage .articlesection header .text .article-subtitle {
margin-bottom: 16px;
margin-top: 10px;
overflow: hidden;
}
.splitpage .articlesection header .article-image {
height: 160px;
width: 242px;
}
.splitpage .itemlistsection, .splitpage .articlesection {
-ms-grid-column: 2;
visibility: hidden;
}
.splitpage .primarycolumn {
-ms-grid-column: 1;
visibility: visible;
}
}
@media screen and (-ms-view-state: fullscreen-portrait) {
.splitpage {
-ms-grid-columns: 1fr 0px;
}
.splitpage .itemlistsection {
margin-left: 86px;
}
.splitpage .itemlistsection .itemlist .win-vertical.win-viewport .win-container {
margin-right: calc(100% - 510px);
}
.splitpage .articlesection {
-ms-grid-row: 2;
-ms-grid-row-span: 1;
margin-left: 100px;
padding-right: 100px;
}
.splitpage .articlesection .header {
margin-top: 0;
}
.splitpage .itemlistsection, .splitpage .articlesection {
-ms-grid-column: 2;
visibility: hidden;
}
.splitpage .primarycolumn {
-ms-grid-column: 1;
visibility: visible;
}
}
split.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>splitPage</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<link href="/css/default.css" rel="stylesheet" />
<link href="/pages/split/split.css" rel="stylesheet" />
<script src="/js/data.js"></script>
<script src="/pages/split/split.js"></script>
</head>
<body>
<!-- This template is used to display each item in the ListView declared below. -->
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
<div class="item">
<div class="item-date">
<p class="item-month" data-win-bind="innerHTML: month"></p>
<span class="item-day" data-win-bind="innerHTML: day"></span> |
<span class="item-year" data-win-bind="innerHTML: year"></span>
</div>
<div class="item-info">
<h3 class="item-title win-type-ellipsis" data-win-bind="textContent: title"></h3>
<h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: author"></h6>
</div>
</div>
</div>
<!-- The content that will be loaded and displayed. -->
<div class="splitpage fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle"></span>
</h1>
</header>
<div class="itemlistsection" aria-label="List column">
<div class="itemlist win-selectionstylefilled" aria-label="List of this group's items" data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'single', swipeBehavior: 'none', tapBehavior: 'toggleSelect' }"></div>
</div>
<div class="articlesection" aria-atomic="true" aria-label="Item detail column" aria-live="assertive">
<article>
<div class="article-content" data-win-bind="innerHTML: content"></div>
</article>
</div>
</div>
</body>
</html>
split.js
(function () {
"use strict";
var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
var binding = WinJS.Binding;
var nav = WinJS.Navigation;
var ui = WinJS.UI;
var utils = WinJS.Utilities;
// The selected item
var post;
function displayFullView() {
// Display the selected item in the item detail page
nav.navigate('/pages/itemDetail/itemDetail.html', { item: post });
}
ui.Pages.define("/pages/split/split.html", {
/// <field type="WinJS.Binding.List" />
_items: null,
_group: null,
_itemSelectionIndex: -1,
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
var listView = element.querySelector(".itemlist").winControl;
// Store information about the group and selection that this page will
// display.
this._group = (options && options.groupKey) ? Data.resolveGroupReference(options.groupKey) : Data.groups.getAt(0);
this._items = Data.getItemsFromGroup(this._group);
this._itemSelectionIndex = (options && "selectedIndex" in options) ? options.selectedIndex : -1;
// Get the first item, which is the default selection
post = this._items.getAt(0);
element.querySelector("header[role=banner] .pagetitle").textContent = this._group.title;
// Set up the ListView.
listView.itemDataSource = this._items.dataSource;
listView.itemTemplate = element.querySelector(".itemtemplate");
listView.onselectionchanged = this._selectionChanged.bind(this);
listView.layout = new ui.ListLayout();
this._updateVisibility();
if (this._isSingleColumn()) {
if (this._itemSelectionIndex >= 0) {
// For single-column detail view, load the article.
binding.processAll(element.querySelector(".articlesection"), this._items.getAt(this._itemSelectionIndex));
}
} else {
if (nav.canGoBack && nav.history.backStack[nav.history.backStack.length - 1].location === "/pages/split/split.html") {
// Clean up the backstack to handle a user snapping, navigating
// away, unsnapping, and then returning to this page.
nav.history.backStack.pop();
}
// If this page has a selectionIndex, make that selection
// appear in the ListView.
listView.selection.set(Math.max(this._itemSelectionIndex, 0));
}
// Display the appbar and show the Full View button
var appbar = document.getElementById('appbar');
var appbarCtrl = appbar.winControl;
appbarCtrl.showCommands(["view"], false);
// Register the event handler for the Full View button
document.getElementById('view').addEventListener("click", displayFullView, false);
},
unload: function () {
this._items.dispose();
},
// This function updates the page layout in response to viewState changes.
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
var listView = element.querySelector(".itemlist").winControl;
var firstVisible = listView.indexOfFirstVisible;
this._updateVisibility();
var handler = function (e) {
listView.removeEventListener("contentanimating", handler, false);
e.preventDefault();
}
if (this._isSingleColumn()) {
listView.selection.clear();
if (this._itemSelectionIndex >= 0) {
// If the app has snapped into a single-column detail view,
// add the single-column list view to the backstack.
nav.history.current.state = {
groupKey: this._group.key,
selectedIndex: this._itemSelectionIndex
};
nav.history.backStack.push({
location: "/pages/split/split.html",
state: { groupKey: this._group.key }
});
element.querySelector(".articlesection").focus();
} else {
listView.addEventListener("contentanimating", handler, false);
if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
listView.indexOfFirstVisible = firstVisible;
}
listView.forceLayout();
}
} else {
// If the app has unsnapped into the two-column view, remove any
// splitPage instances that got added to the backstack.
if (nav.canGoBack && nav.history.backStack[nav.history.backStack.length - 1].location === "/pages/split/split.html") {
nav.history.backStack.pop();
}
if (viewState !== lastViewState) {
listView.addEventListener("contentanimating", handler, false);
if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
listView.indexOfFirstVisible = firstVisible;
}
listView.forceLayout();
}
listView.selection.set(this._itemSelectionIndex >= 0 ? this._itemSelectionIndex : Math.max(firstVisible, 0));
}
},
// This function checks if the list and details columns should be displayed
// on separate pages instead of side-by-side.
_isSingleColumn: function () {
var viewState = Windows.UI.ViewManagement.ApplicationView.value;
return (viewState === appViewState.snapped || viewState === appViewState.fullScreenPortrait);
},
_selectionChanged: function (args) {
var listView = document.body.querySelector(".itemlist").winControl;
var details;
// By default, the selection is restriced to a single item.
listView.selection.getItems().done(function updateDetails(items) {
if (items.length > 0) {
this._itemSelectionIndex = items[0].index;
// Get the item selected by the user
post = this._items.getAt(this._itemSelectionIndex);
if (this._isSingleColumn()) {
// If snapped or portrait, navigate to a new page containing the
// selected item's details.
nav.navigate("/pages/split/split.html", { groupKey: this._group.key, selectedIndex: this._itemSelectionIndex });
} else {
// If fullscreen or filled, update the details column with new data.
details = document.querySelector(".articlesection");
binding.processAll(details, items[0].data);
details.scrollTop = 0;
}
}
}.bind(this));
},
// This function toggles visibility of the two columns based on the current
// view state and item selection.
_updateVisibility: function () {
var oldPrimary = document.querySelector(".primarycolumn");
if (oldPrimary) {
utils.removeClass(oldPrimary, "primarycolumn");
}
if (this._isSingleColumn()) {
if (this._itemSelectionIndex >= 0) {
utils.addClass(document.querySelector(".articlesection"), "primarycolumn");
document.querySelector(".articlesection").focus();
} else {
utils.addClass(document.querySelector(".itemlistsection"), "primarycolumn");
document.querySelector(".itemlist").focus();
}
} else {
document.querySelector(".itemlist").focus();
}
}
});
})();