Controls (HTML with JavaScript)

Add new features to your Windows Store app, such as custom commands and enhanced navigation support, with the new HTML and JavaScript controls in Windows 8.1. Updates to existing controls make them easier to use and add more features, such as drag-and-drop support. These new controls and control updates make it easier than ever to create a full-featured app.

New controls and control updates

Windows 8.1 and the Windows Library for JavaScript 2.0 introduce these new controls and features:

Windows 8.1 and the Windows Library for JavaScript 2.0 include updates for these existing controls:

Using the Windows Library for JavaScript 2.0

New Microsoft Visual Studio 2013 projects automatically include the Windows Library for JavaScript 2.0. To use the Windows Library for JavaScript 2.0 in a project that was created with Windows 8, replace your existing Windows Library for JavaScript 1 references.


    <!-- WinJS style sheets (include one) -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet">
    <link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet">

    <!-- WinJS code -->
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

...with references to the Windows Library for JavaScript 2.0:


    <!-- WinJS style sheets (include one) -->
    <link rel="stylesheet" href="//Microsoft.WinJS.2.0/css/ui-dark.css" />
    <link rel="stylesheet" href="//Microsoft.WinJS.2.0/css/ui-light.css" />

    <!-- WinJS code -->
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

Visual Studio 2013 can automatically upgrade your project for you, or you can make these additional updates manually:

  • Add a reference to the Windows 8.1 Library for JavaScript to your project.

  • In your app manifest, update the OSMinVersion and OSMaxVersionTested values to 6.3.0:

    
      <Prerequisites>
        <OSMinVersion>6.3.0</OSMinVersion>
        <OSMaxVersionTested>6.3.0</OSMaxVersionTested>
      </Prerequisites>
    
    

AppBarCommand

[Get the HTML AppBar control sample now.]

In Windows 8.1, you can create custom app bar commands in Windows Store apps using JavaScript by using a new type of AppBarCommand named content.

This feature simplifies the process of creating an app bar with custom content by enabling you to put custom content in the commands layout. You can take advantage of the full built-in support for app bar commands with custom content, including keyboarding, command alignment, and animations for dynamically showing and hiding commands.

When placed in the commands layout, the content type AppBarCommand supports many of the same features as the default app bar commands.

  • Keyboarding (using tab, arrow, home. and end keys) is enabled between default app bar commands and the custom AppBarCommand.

  • App bar scaling works correctly with the new content type AppBarCommand. Text labels for commands are dropped dynamically as the app is resized to be smaller.

BackButton

Windows 8.1 and the Windows Library for JavaScript 2.0 add more navigation support to the platform in the form of controls for your apps. One of these controls is the BackButton.

The BackButton provides an easy way for you to add backward navigation to your app. It's simple to create a BackButton control.


<button data-win-control="WinJS.UI.BackButton" ></button>

The new BackButton control

The BackButton automatically checks the navigation stack to determine whether the user can navigate backwards. If there is nothing to navigate back to, the button disables itself. When the user clicks the button or uses keyboard shortcuts (such as Alt+Left or the BrowserBack keys), it automatically calls the WinJS.Navigation.back function to navigate backwards. You don't have to write any code.

Hub

[Get the HTML Hub control sample now.]

To help provide a more consistent navigation experience, Windows 8.1 and the Windows Library for JavaScript 2.0 add the Hub control.

Many Windows Store apps use the hub navigation pattern, a hierarchical system of navigation. This pattern is best for apps with large content collections or many distinct sections of content for a user to explore.

The essence of hub design is the separation of content into different sections and different levels of detail. Hub pages are the user's entry point to the app. Here content is displayed in a horizontally or vertically panning view that enables users to get a glimpse of what's new and available. The hub consists of different categories of content, each of which maps to the app's section pages. Each section should bubble up content or functionality. The hub should offer a lot of visual variety, engage users, and draw them in to different parts of the app.

A hub page

 

With Windows 8.1, the Hub control makes it easy to create a hub page. To get started quickly creating an app with a Hub page, use the Hub App template in Visual Studio 2013.

Creating a hub

To create a hub, you add a Hub control and a HubSection object for each section the hub contains. Each HubSection can contain any type of content, including other Windows Library for JavaScript controls. You use the header property to specify the section header. Section headers can be static or interactive. Interactive headers show a chevron that can be hidden and raise events when the user interacts with them.

This example defines a Hub that has three sections.


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>hubPage</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/hub/hub.css" rel="stylesheet" />
    <script src="/js/data.js"></script>
    <script src="/pages/hub/hub.js"></script>
</head>
<body>
    <div class="hubpage fragment">
        <header aria-label="Header content" role="banner">
            <button data-win-control="WinJS.UI.BackButton"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle">Hub example</span>
            </h1>
        </header>

        <section class="hub" aria-label="Main content" role="main" data-win-control="WinJS.UI.Hub">
            <!-- Customize the Hub control by modifying the HubSection controls here. -->


            <div class="section1" data-win-control="WinJS.UI.HubSection" data-win-options="{ isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'Section1'} }">
                <img src="/images/gray.png" width="420" height="280" />
                <div class="subtext win-type-x-large secondary-text" data-win-res="{ textContent: 'Section1Subtext' }"></div>
                <div class="win-type-medium" data-win-res="{ textContent: 'DescriptionText' }"></div>
                <div class="win-type-small secondary-text">
                    <span data-win-res="{ textContent: 'Section1Description' }"></span>
                    <span data-win-res="{ textContent: 'Section1Description' }"></span>
                    <span data-win-res="{ textContent: 'Section1Description' }"></span>
                </div>
            </div>

            <div class="section2" data-win-control="WinJS.UI.HubSection" data-win-res="{ winControl: {'header': 'Section2'} }"
                data-win-options="{ onheaderinvoked: HubPage.section2HeaderNavigate }">
                <div class="itemTemplate" data-win-control="WinJS.Binding.Template">
                    <img src="#" data-win-bind="src: backgroundImage; alt: title" />
                    <div class="item-text">
                        <div class="win-type-medium" data-win-bind="textContent: title"></div>
                        <div class="win-type-xx-small secondary-text" data-win-bind="textContent: subtitle"></div>
                        <div class="win-type-small secondary-text" data-win-bind="textContent: description"></div>
                    </div>
                </div>
                <div class="itemslist" data-win-control="WinJS.UI.ListView" data-win-options="{
                        layout: {type: WinJS.UI.ListLayout2},
                        selectionMode: 'none',
                        itemTemplate: select('.section2 .itemTemplate'),  
                        itemDataSource: HubPage.section2DataSource,
                        oniteminvoked: HubPage.section2ItemNavigate
                    }">
                </div>
            </div>

            <div class="section3" data-win-control="WinJS.UI.HubSection" data-win-options="{ isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'Section3'} }">
                <div class="top-image-row">
                    <img src="/images/gray.png" />
                </div>
                <div class="sub-image-row">
                    <img src="/images/gray.png" />
                    <img src="/images/gray.png" />
                    <img src="/images/gray.png" />
                </div>
                <div class="win-type-medium" data-win-res="{ textContent: 'DescriptionText' }"></div>
                <div class="win-type-small secondary-text">
                    <span data-win-res="{ textContent: 'Section3Description' }"></span>
                    <span data-win-res="{ textContent: 'Section3Description' }"></span>
                </div>
            </div>


        </section>
    </div>
</body>
</html>

That code creates this page.

A hub page

 

When you click the second heading, the app goes to a section page.

A section page

 

Here's the code that performs the navigation.


(function () {
    "use strict";

    var nav = WinJS.Navigation;
    var session = WinJS.Application.sessionState;
    var util = WinJS.Utilities;

    // Get the groups used by the data-bound sections of the hub.
    var section2Group = Data.resolveGroupReference("group1");
    var section5Group = Data.resolveGroupReference("group6");

    WinJS.UI.Pages.define("/pages/hub/hub.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 hub = element.querySelector(".hub").winControl;
            hub.onloadingstatechanged = function (args) {
                if (args.srcElement === hub.element && args.detail.loadingState === "complete") {
                    this._hubReady(hub);
                    hub.onloadingstatechanged = null;
                }
            }.bind(this);

            hub.onheaderinvoked = function (args) {
                args.detail.section.onheaderinvoked(args);
            };

            // TODO: Initialize the page here.
        },

        unload: function () {
            // TODO: Respond to navigations away from this page.
            session.hubScroll = document.querySelector(".hub").winControl.scrollPosition;
        },

        updateLayout: function (element, viewState, lastViewState) {
            /// <param name="element" domElement="true" />

            // TODO: Respond to changes in viewState.
        },

        _hubReady: function (hub) {
            /// <param name="hub" type="WinJS.UI.Hub" />

            WinJS.Resources.processAll();
            if (typeof session.hubScroll === "number") {
                hub.scrollPosition = session.hubScroll;
            }

            // TODO: Initialize the hub sections here.
        },
    });

    function createHeaderNavigator(group) {
        return util.markSupportedForProcessing(function (args) {
            nav.navigate("/pages/section/section.html", { title: this.header, groupKey: group.key });
        });
    }

    function createItemNavigator(group) {
        var items = Data.getItemsFromGroup(group);
        return util.markSupportedForProcessing(function (args) {
            var item = Data.getItemReference(items.getAt(args.detail.itemIndex));
            nav.navigate("/pages/item/item.html", { item: item });
        });
    }

    function getItemsDataSourceFromGroup(group) {
        return Data.getItemsFromGroup(group).dataSource;
    }

    WinJS.Namespace.define("HubPage", {
        section2DataSource: getItemsDataSourceFromGroup(section2Group),
        section2HeaderNavigate: createHeaderNavigator(section2Group),
        section2ItemNavigate: createItemNavigator(section2Group),
        section5DataSource: getItemsDataSourceFromGroup(section5Group),
        section5ItemNavigate: createItemNavigator(section5Group)
    });
})();

You can even use the Hub control with the SemanticZoom control. For additional examples of this and more, see the HTML Hub control sample.

ItemContainer

[Get the HTML ItemContainer Sample now.]

The new ItemContainer control makes it easy to create interactive elements that provide swipe, drag-and-drop, and hover functionality. Just place your content inside the ItemContainer. The ItemContainer can contain standard HTML elements and even other WinJS controls.

The ItemContainer is flexible, making it great for many uses, such as creating rich check-box groups, navigation buttons, and shopping-cart representations.

ItemContainer objects in a nav bar

 

Use an ItemContainer when you want to display items but don't need all the features of the ListView control.

Using the ItemContainer

This example creates two ItemContainer objects and sets their tapBehavior property to toggleSelect so that they can be selected.


<div id="item1"
    data-win-control="WinJS.UI.ItemContainer"
    data-win-options="{tapBehavior: 'toggleSelect'}"
    style="width: 300px;">
    <div style="margin: 10px; padding: 10px; background-color: lightgray">
        <div class="win-type-x-large"
            style="margin-bottom: 5px;">
            Banana
        </div>
        <img src="/images/60banana.png">
        <div>Frozen yogurt</div>
    </div>
</div>
<div id="item2"
    data-win-control="WinJS.UI.ItemContainer"
    data-win-options="{tapBehavior: 'toggleSelect'}"
    style="width: 300px;">
    <div style="margin: 10px; padding: 10px; background-color: lightgray">
        <div class="win-type-x-large"
            style="margin-bottom: 5px;">
            Strawberry
        </div>
        <img src="/images/60Strawberry.png">
        <div>Ice cream</div>
    </div>
</div>

Two ItemContainer objects

 

You can also use an ItemContainer with a Repeater control to generate items from a List; just put the ItemContainer inside your Template control.


<div id="itemTemplate" data-win-control="WinJS.Binding.Template">
    <div  
        data-win-control="WinJS.UI.ItemContainer" 
        data-win-options="{tapBehavior: WinJS.UI.TapBehavior.toggleSelect}"
        style="width: 300px;">
            <div 
                 style=" margin: 10px; padding: 10px; background-color: lightgray">
                <div class="win-type-x-large" 
                    style="margin-bottom: 5px;" 
                    data-win-bind="textContent: title"></div>
                <img src="#" data-win-bind="src: image">
		        <div data-win-bind="textContent: desc"></div>
            </div>
    </div>
</div>

<div data-win-control="WinJS.UI.Repeater" 
    data-win-options="{data: ItemContainerExample.flavorList, 
    template: select('#itemTemplate')}">
</div>

This example defines the data source.


(function () {
    "use strict";

    var basicList = new WinJS.Binding.List(
        [
            { title: "Banana blast", desc: 'Frozen yogurt', image: '/images/60Banana.png'  },
            { title: "Strawberry swirl", desc: 'Ice cream', image: '/images/60Strawberry.png' },
            { title: "Magnificant mint", desc: 'Frozen yogurt', image: '/images/60Mint.png' },
            { title: "Lemon lift", desc: 'Frozen yogurt', image: '/images/60Lemon.png' }
        ]);

    WinJS.Namespace.define("ItemContainerExample",
        {
            flavorList: basicList

        });
})();

ItemContainer objects generated by a Repeater

 

Items are selectable by default. To disable selection, set the ItemContainer control's selectionDisabled property to true.

NavBar

[Get the HTML NavBar control sample now.]

Windows 8.1 and the Windows Library for JavaScript 2.0 introduces a new control to help you provide a consistent and predictable navigation experience: the WinJS.UI.NavBar control.

A NavBar that contains navigation items generated from a data source

 

The NavBar is like an AppBar that's dedicated to navigation commands. (In fact, the NavBar is a subclass of the AppBar.) It can contain a simple list of links, and it can contain several levels of links organized into categories. You can populate the NavBar by hard-coding entries, programmatically updating it, or by using data binding.

The NavBar appears at the top of the app screen when the user needs it. The user invokes the NavBar by performing an edge swipe, pressing the Windows logo key+Z, or right-clicking.

The NavBar also supports vertical layouts and split-navigation items (navigation items that have child navigation options). The NavBar is highly customizable: you can use Cascading Style Sheets (CSS) to style almost any aspect of the NavBar and its contents, and you can also create custom navigation items.

Creating a NavBar

The NavBar has three components:

  • The NavBar itself.

  • A NavBarContainer object, which contains navigation items (NavBarCommand objects) and supports both pagination and panning and scrolling. You can have one or more NavBarContainer objects in a single NavBar. You use NavBarContainer objects to define groups of navigation options.

  • One or more NavBarCommand objects. These are what the user clicks to navigate.

To enable navigation, you can set the NavBarCommand object's location property. When the user clicks the command, the WinJS.Navigation.navigated event fires. Use this event to navigate to the specified location.

Alternatively, you can register for the oninvoked event on the NavBar and use your event handler to perform the navigation action.

This example shows a simple NavBar that contains two navigation items.


<div id="NavBar" data-win-control="WinJS.UI.NavBar">
    <div id="GlobalNav" data-win-control="WinJS.UI.NavBarContainer">
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{
                label: 'Home',
                icon: WinJS.UI.AppBarIcon.home,
                location: '/html/home.html',
                splitButton: false
                }">
            </div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{
                label: 'Your apps',
                icon: WinJS.UI.AppBarIcon.favorite,
                location: '/html/yourapps.html',
                splitButton: false
                }">
            </div>
    </div>
</div>


And here's what that NavBar looks like.

The NavBar

 

You can create a NavBarCommand that contains child NavBarCommand objects. To do that, you set the parent NavBarCommand object's splitButton property to true and then use the splittoggle event to display a Flyout that contains the child NavBarCommand objects. Here's example code for the first part of that.


<div id="useSplit" data-win-control="WinJS.UI.NavBar">
    <div class="globalNav" data-win-control="WinJS.UI.NavBarContainer">
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Home', icon: 'url(../images/homeIcon.png)' }">
        </div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Favorite', icon: WinJS.UI.AppBarIcon.favorite, splitButton: 'true' }">
        </div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Your account', icon: WinJS.UI.AppBarIcon.people }">
        </div>
    </div>
</div>
<div id="contactFlyout" data-win-control="WinJS.UI.Flyout" 
    data-win-options="{ placement: 'bottom' }">
    <div id="contactNavBarContainer" data-win-control="WinJS.UI.NavBarContainer"}">
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Family' }">
        </div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Work' }">
        </div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Friends' }">
        </div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
            data-win-options="{ label: 'Blocked' }">
        </div>  
    </div>
</div>

The next example shows the code that initializes the HTML page and adds the splittoggle event handler, which displays the Flyout that contains the child NavBarCommand objects.


(function () {
    "use strict";
    var navcontainer;

    var page = WinJS.UI.Pages.define("/html/6-UseSplitButton.html", {
        ready: function (element, options) {
            document.body.querySelector('#useSplit').addEventListener('invoked', this.navbarInvoked.bind(this));
            document.body.querySelector('#contactNavBarContainer').addEventListener('invoked', this.navbarInvoked.bind(this));

            var navBarContainerEl = document.body.querySelector('#useSplit .globalNav');
            if (navBarContainerEl) {
                this.setupNavBarContainer();
            } else {
                var navBarEl = document.getElementById('useSplit');
                navBarEl.addEventListener('childrenprocessed', this.setupNavBarContainer.bind(this));
            }
        },

        navbarInvoked: function (ev) {
            var navbarCommand = ev.detail.navbarCommand;
            WinJS.log && WinJS.log(navbarCommand.label + " NavBarCommand invoked", "sample", "status");
            document.querySelector('select').focus();
        },

        setupNavBarContainer: function () {
            var navBarContainerEl = document.body.querySelector('#useSplit .globalNav');

            navBarContainerEl.addEventListener("splittoggle", function (e) {
                var flyout = document.getElementById("contactFlyout").winControl;
                var navbarCommand = e.detail.navbarCommand;
                if (e.detail.opened) {
                    flyout.show(navbarCommand.element);
                    var subNavBarContainer = flyout.element.querySelector('.win-navbarcontainer');
                    if (subNavBarContainer) {
                        // Switching the navbarcontainer from display none to display block requires 
                        // forceLayout in case there was a pending measure.
                        subNavBarContainer.winControl.forceLayout();
                        // Reset back to the first item.
                        subNavBarContainer.currentIndex = 0;
                    }
                    flyout.addEventListener('beforehide', go);
                } else {
                    flyout.removeEventListener('beforehide', go);
                    flyout.hide();
                }
                function go() {
                    flyout.removeEventListener('beforehide', go);
                    navbarCommand.splitOpened = false;
                }
            });
        }
    });
})();

(For the full code, see the HTML NavBar sample.)

Here's what the NavBar looks like with the split button open:

A split NavBarCommand

 

You can bind a NavBarContainer to a data source. To do so, create a List that contains data that describes the navigation commands and use it to set the NavBarContainer object's data property. This example defines the data for use by the NavBarContainer.



(function () {
    "use strict";
    var page = WinJS.UI.Pages.define("/html/2-UseData.html", {
        init: function (element, options) {
            var categoryNames = ["Picks for you", "Popular", "New Releases", "Top Paid", "Top Free",
            "Games", "Social", "Entertainment", "Photo", "Music & Video",
            "Sports", "Books & Reference", "News & Weather", "Health & Fitness", "Food & Dining",
            "Lifestyle", "Shopping", "Travel", "Finance", "Productivity",
            "Tools", "Secuirty", "Business", "Education", "Government"];

            var categoryItems = [];
            for (var i = 0; i < categoryNames.length; i++) {
                categoryItems[i] = {
                    label: categoryNames[i]
                };
            }

            Data.categoryList = new WinJS.Binding.List(categoryItems);
        },

        ready: function (element, options) {
            document.body.querySelector('#useTemplate').addEventListener('invoked', this.navbarInvoked.bind(this));
        },

        navbarInvoked: function (ev) {
            var navbarCommand = ev.detail.navbarCommand;
            WinJS.log && WinJS.log(navbarCommand.label + " NavBarCommand invoked", "sample", "status");
            document.querySelector('select').focus();
        }
    });
})();



The next example shows the HTML that creates the NavBar and NavBarContainer objects.



<div id="useTemplate" data-win-control="WinJS.UI.NavBar">
    <div class="globalNav" data-win-control="WinJS.UI.NavBarContainer">
        <div data-win-control="WinJS.UI.NavBarCommand" 
             data-win-options="{ label: 'Home', icon: 'url(../images/homeIcon.png)' }">
        </div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
             data-win-options="{ label: 'Favorite', icon: 'favorite' }"></div>
        <div data-win-control="WinJS.UI.NavBarCommand" 
             data-win-options="{ label: 'Your account', icon: 'people' }"></div>
    </div>
    <div class="categoryNav" 
        data-win-control="WinJS.UI.NavBarContainer" 
        data-win-options="{ data: Data.categoryList, maxRows: 3 }">
    </div>
</div>



(For the full code, see the HTML NavBar sample.)

When you run the code, it creates this NavBar.

A NavBar that contains navigation items generated from a data source

 

Although it's not shown here, you can also use a WinJS.Binding.Template object with a data source to generate nav bar items.

Repeater

[Get the HTML Repeater control sample now.]

The Repeater is a simple, easy-to-use WinJS control that uses a template to generate HTML markup from a set of data. The template can contain nearly any HTML markup and WinJS controls. You can even nest Repeater controls inside Repeater controls.

Use the Repeater to generate custom lists and tables. Here's an example of a weather forecast created by a Repeater.

repeater control

 

The Repeater isn't a replacement for the ListView control. It's more flexible, but doesn't provide some of the advanced features of the ListView, such as control over how data items are loaded.

Using the Repeater

A Repeater generates its data from a List. This example creates a List that contains a few simple items.


(function () {
    "use strict";

    var basicList2 = new WinJS.Binding.List(
        [
            { title: "Item 1" },
            { title: "Item 2" },
            { title: "Item 3" },
            { title: "Item 4" }
        ]);

    WinJS.Namespace.define("RepeaterExample",
        {
            basicList: basicList2

        });
})();

To specify the markup that the Repeater generates, you define a template. You can create a template in markup or use a templating function. This example creates a template in markup. It data-binds the title field of the data source to the text content of an li element.


<div id="listTemplate" data-win-control="WinJS.Binding.Template">
    <li data-win-bind="textContent: title"></li>
</div>

The next example creates the Repeater itself.


<ul data-win-control="WinJS.UI.Repeater" 
    data-win-options="{data: RepeaterExample.basicList, 
    template: select('#listTemplate')}">
</ul>

When you run the app, the Repeater generates an li element for each item in the data list.

A list generated by the Repeater control

 

WebView with SmartScreen

[Get the HTML WebView control sample now.]

In Windows 8, you could use the iframe element to host web-based content, but it didn't provide much content isolation or navigation functionality. Windows 8.1 introduces the new WebView control, which makes it significantly easier to host web-based content in your apps.

Here are a few of the improvements the WebView offers over using an iframe to display web-based content:

  • Support for HTML5

    Pages hosted in a WebView can access most HTML5 functionality. (However, the WebView can't access IndexedDB, HTML5 app cache, the Geolocation API, or the Clipboard API.)

  • Improved navigation support

    The WebView has its own separate history stack and provides several methods for navigating forward and backward, and for reloading the current page.

  • Support for sites that don't work inside frames

    The WebView can display sites that don't work inside frame or iframe elements.

Using the WebView to load content

To create a WebView control, you create an x-ms-webview element.


<x-ms-webview id="webview">
</x-ms-webview>


There are several ways you can use the WebView to load content:

  • Use the WebView control's src property, the navigate method, or the navigateWithHttpRequestMessage method to navigate to a URI. This example uses the src property to navigate to a URI.

    
    <x-ms-webview id="webview" src="http://go.microsoft.com/fwlink/?LinkId=294155" 
        style="width: 400px; height: 400px;">
    </x-ms-webview>
    
    
    
  • Use the navigateToString method to load an arbitrary string of HTML.

    
    var htmlString = "<!DOCTYPE html>" +
            "<html>" +
            "<head><title>Simple HTML page</title></head>" +
            "<body>" +
                "<h1>Hi!</h1>" +
                "<p>This is a simple HTML page.</p>" +
            "</body>" +
            "</html>";
    document.getElementById("webview").navigateToString(
        htmlString);
    
    
  • You can use the navigate method with the ms-appdata:// protocol to load HTML content stored in the app's state folders.

    
     document.getElementById("webview").navigate(
        "ms-appdata:///local/NavigateToState/simple_example.html");
    
    
  • For HTML-based file formats, it can sometimes be useful to stream relative references as they are needed, such as for encrypted HTML content that cannot be natively rendered by the WebView control. Use the buildLocalStreamUri and navigateToLocalStreamUri methods to display content from a stream. (You must also implement a custom Windows Runtime object that uses the IUriToStreamResolver interface.)

    
    var contentUri = document.getElementById("webview").buildLocalStreamUri(
        "NavigateToStream", "simple_example.html");
    var uriResolver = new SDK.WebViewSampleCS.StreamUriResolver();
    document.getElementById("webview").navigateToLocalStreamUri(contentUri, uriResolver);
    
    

For complete examples, see the HTML WebView sample.

Drag-and-drop support for the ListView

[Get the HTML ListView drag-and-drop and reordering sample now.]

With Windows Library for JavaScript 2.0, the ListView adds support for drag-and-drop operations. This new support is compatible with HTML 5 drag-and-drop functionality. You can drag between two ListView controls, between an ItemContainer and a ListView, and between any HTML element and the ListView. You can let the user drop items into a specific location in the ListView, or you can control where dropped items are inserted, such as by re-sorting items in the ListView after a new item is added.

Dragging an item from the ListView

To enable dragging an item from the ListView to an HTML 5 drop target, you:

  1. Set the itemsDraggable property of the ListView to true.

  2. Handle the ListView control's itemdragstart event. In your event handler, get a dataTransfer object from the event object's detail property. Use the dataTransfer object's setData method to specify how the data is to be transferred and which data to transfer.

  3. Handle the drop target's dragover event. In your event handler, use the preventDefault method of the event object to tell the system that you are accepting the drop. Otherwise, the drag operation will not be accepted by the drop target.

  4. Handle the drop target's drop event. In your event handler, get a dataTransfer object from the event object's detail property. Use the dataTransfer object's getData property to retrieve the data being transferred. Use this data to update the drop target. Be careful not to accept drags from intrinsically draggable elements in your app, such as selected text and img elements.

Here's a set of examples that show how to enable dragging an item from the ListView. The first example defines the HTML markup.


<div id="myDropTarget" class="DnDItem">
    <div id="myTargetContents">
        <p>
            HTML 5 Drop Target
        </p>
        <br />
        <div id="myPlusSign" class="drop-ready">+ </div>
        <br />
        <p>
            Drop Items Here
        </p>
    </div>
</div>

<!-- Simple template for the ListView instantiation  -->
<div id="smallListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
    <div class="smallListIconTextItem">
        <img src="#" class="smallListIconTextItem-Image" data-win-bind="src: picture" draggable="false" />
        <div class="smallListIconTextItem-Detail">
            <h4 data-win-bind="innerText: title"></h4>
            <h6 data-win-bind="innerText: text"></h6>
        </div>
    </div>
</div>

<!-- The declarative markup necessary for ListView instantiation -->
<!-- Call WinJS.UI.processAll() in your initialization code -->
<div id="listView"
    class="win-selectionstylefilled"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{ 
        itemDataSource: myData.dataSource,
        selectionMode: 'none', 
        itemTemplate: smallListIconTextTemplate,
        itemsDraggable: true,
        layout: { type: WinJS.UI.GridLayout } 
    }">
</div>

Here is the CSS for the drag-and-drop operation.


.drop-ready #myPlusSign
{
    opacity: 1;
}

#myPlusSign
{
     font-size:100px;
     font-weight:bolder;
     color: blue;
     opacity: 0;
}

The next example shows the code that enables the drag-and-drop functionality.


(function () {
    "use strict";
    var page = WinJS.UI.Pages.define("/html/scenario2.html", {
        ready: function (element, options) {

            listView.addEventListener("itemdragstart", function (eventObject) {
                eventObject.detail.dataTransfer.setData("Text", JSON.stringify(eventObject.detail.dragInfo.getIndices()));
            });

            var dropTarget = element.querySelector("#myDropTarget");
            dropTarget.addEventListener("dragover", function (eventObject) {
                // Allow HTML5 drops.
                eventObject.preventDefault();
            });

            dropTarget.addEventListener("dragenter", function (eventObject) {
                WinJS.Utilities.addClass(dropTarget, "drop-ready");
            });

            dropTarget.addEventListener("dragleave", function (eventObject) {
                WinJS.Utilities.removeClass(dropTarget, "drop-ready");
            });

            dropTarget.addEventListener("drop", function (eventObject) {
                // Get indicies -> keys of items that were trashed, and remove from datasource.
                WinJS.Utilities.removeClass(dropTarget, "drop-ready");
                var indexSelected = JSON.parse(eventObject.dataTransfer.getData("Text"));
                var listview = document.querySelector("#listView").winControl;
                var ds = listview.itemDataSource;

                ds.itemFromIndex(indexSelected[0]).then(function (item) {
                    WinJS.log && WinJS.log("You dropped the item at index " + item.index + ", "
                    + item.data.title, "sample", "status");
                });
            });

        }
    });

})();


For the complete code, see the HTML ListView drag-and-drop and reordering sample.

Dropping an item into the ListView

To drop an element into a specific location within the ListView, you:

  1. Set the draggable property of the HTML element (the drag source) to true.

  2. Handle the drop target's dragstart event. In your event handler, get a dataTransfer object from the event object. Use the dataTransfer object's setData method to specify how the data is to be transferred and which data to transfer.

  3. Handle the ListView control's itemdragenter event. In your event handler, use the preventDefault method of the event object to tell the system that you're accepting the drop. Otherwise, the drag operation might have unpredictable results.

  4. Handle the ListView control's itemdragdrop event. In your event handler, get a dataTransfer object from the event object's detail property. Use the dataTransfer object's getData property to retrieve the data being transferred. Use this data to update the ListView.

Here's a set of examples that show how to enable dropping an item into the ListView. The first example defines the HTML markup.


<div id="myDragSource" class="DnDItem">
    <div id="mySourceContents">
        <p>
            HTML 5 Drag Source
        </p>
        <br />
        <br />
        <br />
        <div id="myDragContent" class="smallListIconTextItem" draggable="true">
            <img id="myImg" src="/images/60Tree.png" class="smallListIconTextItem-Image" draggable="false" />
            <div class="smallListIconTextItem-Detail">
                <h4 id="myItemTitle">Drag Me</h4>
            </div>
        </div>
    </div>
</div>

<!-- Simple template for the ListView instantiation  -->
<div id="smallListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
    <div class="smallListIconTextItem">
        <img src="#" class="smallListIconTextItem-Image" data-win-bind="src: picture" draggable="false" />
        <div class="smallListIconTextItem-Detail">
            <h4 data-win-bind="innerText: title"></h4>
            <h6 data-win-bind="innerText: text"></h6>
        </div>
    </div>
</div>

<!-- The declarative markup necessary for ListView instantiation -->
<!-- Call WinJS.UI.processAll() in your initialization code -->
<div id="listView"
    class="win-selectionstylefilled"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{ 
        itemDataSource: myData.dataSource,
        selectionMode: 'none',
        itemTemplate: smallListIconTextTemplate,
        itemsReorderable: true,
        layout: { type: WinJS.UI.GridLayout } 
    }">
</div>

The next example shows the code that enables the drag-and-drop functionality.


(function () {
    "use strict";
    var page = WinJS.UI.Pages.define("/html/scenario3.html", {
        ready: function (element, options) {

            myDragContent.addEventListener("dragstart", function (eventObject) {
                var dragData = { sourceElement: myDragContent.id, data: myItemTitle.innerText, imgSrc: myImg.src };
                eventObject.dataTransfer.setData("Text", JSON.stringify(dragData));
            });

            listView.addEventListener("itemdragenter", function (eventObject) {
                if (eventObject.detail.dataTransfer.types.contains("Text")) {
                    eventObject.preventDefault();
                }
            });

            listView.addEventListener("itemdragdrop", function (eventObject) {
                var dragData = JSON.parse(eventObject.detail.dataTransfer.getData("Text"));
                if (dragData && dragData.sourceElement === myDragContent.id) {
                    var newItemData = { title: dragData.data, text: ("id: " + dragData.sourceElement), 
                                        picture: dragData.imgSrc };
                    // insertAfterIndex tells us where in the list to add the new item.
                    // If we're inserting at the start, insertAfterIndex is -1. 
                    // Adding 1 to insertAfterIndex gives us the nominal index in the array to insert the new item.
                    myData.splice(eventObject.detail.insertAfterIndex + 1, 0, newItemData);
                } else {
                    // Throw error that illegal content was dropped.
                }
            });
        }
    });
})();


For the complete code, see the HTML ListView drag-and-drop and reordering sample.

Reorder items in the ListView

Being able to reorder content helps users feel in control. The new itemsReorderable property makes it easy to let users change the order of items in a ListView. Just set itemsReorderable to true to let users drag items inside the ListView; no other code is required.

Note  To fully enable reordering items in a grouped ListView, you must also respond to the itemdragdrop event and insert the item properly into the correct location.

Note  For reordering to work, your data source must support reordering.

This example creates a ListView that supports item reordering.


<style type="text/css">
    .win-listview {
        margin: 20px;
        border: 2px solid gray;
        Width: 500px; 
    }

    .standardItem {
        width: 150px;
        height: 150px;
        background-color: #0aaddd;
        padding: 5px; 
    }

</style>

<div id="template" data-win-control="WinJS.Binding.Template">
    <div class="standardItem" data-win-bind="textContent: title" ></div>
</div>
<div
    id="reorderableListView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{
    itemDataSource: ListViewExamples.dataList.dataSource, 
    itemTemplate: select('#template'), 
    layout: {type: WinJS.UI.GridLayout},
    itemsReorderable: true 
    }">
</div>

The next example defines the data source that the ListView uses.


(function () {
    "use strict";

    var dataList =
        new WinJS.Binding.List(
             [{ title: "Item 1" },
              { title: "Item 2" },
              { title: "Item 3" },
              { title: "Item 4" }]);

    WinJS.Namespace.define("ListViewExamples",
        {
            dataList: dataList
        })

})();


When the code runs, the user can reorder ListView items by dragging them.

ListView reordering

New ListView layout: CellSpanningLayout

With Windows Library for JavaScript 1.0, if you wanted a ListView to contain items of multiple sizes, you used a GridLayout. For the Windows Library for JavaScript 2.0, we've added a new layout specifically for creating multi-sized grids: the CellSpanningLayout.

This example defines the data source and the itemInfo and groupInfo methods for a ListView that uses a CellSpanningLayout. Every item in the ListView has a size of 250 pixels by 250 pixels except for the first item, which has a height of 510 pixels.


(function () {
    "use strict";

    var unorderedList =
        new WinJS.Binding.List(
             [{ title: "Item 1", cssClass: "tallItem" },
              { title: "Item 2", cssClass: "standardItem" },
              { title: "Item 3", cssClass: "standardItem" },
              { title: "Item 4", cssClass: "standardItem" }]);

    function myItemInfo(itemIndex) {
        var size = { width: 250, height: 250 };
        if (itemIndex === 0) {
            size.height = 510;
        }

        return size;
    };

    function myGroupInfo(groupInfo) {
        return {
            enableCellSpanning: true,
            cellWidth: 250,
            cellHeight: 250
        };
    };

    WinJS.Utilities.markSupportedForProcessing(myItemInfo);
    WinJS.Utilities.markSupportedForProcessing(myGroupInfo);

    WinJS.Namespace.define("ListViewExamples",
        {
            unorderedList: unorderedList,
            myItemInfo: myItemInfo,
            myGroupInfo: myGroupInfo
        })


})();


The next example shows the HTML for creating the ListView and the WinJS.Binding.Template.


<style type="text/css">
    .win-listview {
        margin: 5px;
        border: 2px solid gray; 
    }

    .standardItem {
        width: 250px;
        height: 250px;
        background-color: #999999;
        padding: 5px; 
    }

    .tallItem {
        width: 250px;
        height: 510px;
        background-color: #0aaddd;
        padding: 5px; 
    }
</style>

<div id="template" data-win-control="WinJS.Binding.Template">
    <div data-win-bind="className: cssClass; textContent: title" ></div>
</div>

<div
    id="cellSpanningListView"
    data-win-control="WinJS.UI.ListView"
    data-win-options="{
    itemDataSource: ListViewExamples.unorderedList.dataSource, 
    itemTemplate: select('#template'), 
    layout: {type: WinJS.UI.CellSpanningLayout, 
    itemInfo: ListViewExamples.myItemInfo, 
    groupInfo: ListViewExamples.myGroupInfo}
    }">
</div>


Here's what the ListView looks like.

A ListView that uses CellSpanningLayout

Other ListView updates

Windows 8.1 includes even more improvements to the ListView control.

Better accessibility for headers

Headers in a grouped ListView now support keyboard navigation and keyboard and mouse interaction. You don't need to make any changes to your code to get these new features.

(For more info about creating groups, see How to group items in a ListView.)

Note  If you made your header invocable in Windows Library for JavaScript 1.0 by including a link or a button in it, users will not be able to invoke the header with the keyboard when you switch to Windows Library for JavaScript 2.0. To fix this issue, handle the ongroupheaderinvoked event and use it to perform the header action instead of using a button or link.

Updates to the layout interface

The ListView now has a new set of layout interfaces that make it easier to create your own custom layout: ILayout2 and ISiteLayout2. When you implement these interfaces, you can use standard CSS layouts as a part of your implementation.

Updates to ListLayout and GridLayout

We've updated ListLayout and GridLayout to improve their overall performance, especially their panning performance. You don't need to make any changes to your code to take advantage of these improvements.

Other WinJS updates

Binding and WinJS.Binding.Template updates

The Windows Library for JavaScript 2.0 uses a new, more efficient system for processing Template objects, and it improves performance significantly. With the new system, data binding and control instantiation happen in a more fluid, parallel process rather than in series, as they did in Windows Library for JavaScript 1.0. If your code depends on the legacy serial processing behavior, we recommend changing your code to take advantage of faster template processing. However, you can use the disableOptimizedProcessing property to restore the old behavior if you can't change your code.

The dispose API

The dispose model is a new pattern that allows elements and controls to release resources at the end of their lifetime to prevent memory leaks. An element or control can implement it optionally. Windows Library for JavaScript 2.0 controls that have resources to release now implement this API.

To take advantage of the dispose model, call the control's dispose method when the control is no longer needed, such as when you're navigating away from a page or when the app is shutting down.

 

 

Show:
© 2014 Microsoft. All rights reserved.