sobota, 26 listopada 2011

Notatki o Windows 8 - odc.3

Kontynuacja tematu o tworzeniu UI w HTML5. Oprócz kilku uwag o skalowaniu, wiele istotnych i ciekawych informacji o nawigacji oraz o tzw. fragmentach pozwalających pisać fragmenty stron poza docelową stroną.

Don't programmatically unsnap your app to get the user's attention. Unsnapping should be reserved only for situations when the user is trying to use a feature that is not available in the snapped state. If your app has snapped views for all pages in the app, you shouldn't need to programmatically unsnap at all. Snapping and unsnapping should never destroy the user's work or state.

When UI would otherwise be too small to touch and when text gets too small to read, Windows scales the system and app UI to a scale percentage: 100% when no scaling is applied, 140% for 1920x1080 slates, 180% for 2560x1440 slates.

Use SVG for Javascript apps and XAML for C#/C++/VB apps. Windows scales these formats for you automatically, without noticeable artifacts. For bitmap formats and saved inside of the app package, save multiple images for each scale and name your files using the .scale naming convention. Windows loads the right image for the current scale automatically.

foo.scale-140.jpg lub \scale-140\foo.jpg

If your application is a JavaScript app and you have a remote web image, use the CSS @media min-resolution media query with a background-image to replace images at runtime.

If your application loads user images from the file system, you should use the File Access Thumbnail API which automatically retrieves a thumbnail for files on the file system that corresponds to the current scale.

Manually load images based upon scale percentage at runtime. If your application is loading images at runtime using code, use the Windows Runtime API to determine the scale and manually load images based upon scale percentage.

Specify width and height for your images. You should ensure to specify a width and height on images instead of using auto sizing for images to prevent layouts from changing when larger images are loaded.

Use typographic grid-units and sub-units. Where possible, you should use the typographic grid defined sizes of 20px for major grid-units and 5px for minor grid-units to ensure that layouts to not experience pixel shifting due to pixel rounding. Any sized unit that is divisible by 5px will not experience pixel rounding.

Don't use smaller images that are scaled up. Because images are scaled by default, images look blurry at 140% scale on HD slates if only 100% scale images are available.

Don’t use larger images that are scaled down. Larger images that are scaled down show scaling artifacts and jagged edges on standard slates.

Avoid specifying sizes that aren't multiples of 5px Units that aren't multiples of 5px can experience pixel shifting when scaled to 140% and 180%.

CSS3 Flexible Box layout, CSS3 Grid alignment, CSS3 Multi-column layout, CSS3 Connected Frames layout

Nawigacja (JS)

Hyperlinks & iframes

page2.html, ms-wwa://package name/file path, ms-wwa:///file path

Metro style apps using JavaScript don't automatically provide navigation controls, so when you navigate to a new page, there's no way to get back to the first page unless you create a link or other navigation mechanism that takes you back. In general, you should avoid navigating away from your entry page. The preferred approach is to use an iframe or the WinJS.UI.Fragments functions to load the target page's content inside the current page.

<p><a href="ms-wwa:///page2.html" target="targetFrame">Go to page 2</a></p>

<iframe name="targetFrame">
</iframe>

You can also link to external pages—with some restrictions: you can display an external page in an iframe, but you can't navigate your top-level page to an external website. The link opens in the web browser rather than inside your application.That's because the URI isn't considered part of the application's content. To make a URI part of the application's content, you update the ApplicationContentUriRules element (a child of the Application element) in your app's package manifest. The ApplicationContentUriRules element contains one or more rule entries, each of which contains a match attribute that specifies a URI match and a type attribute that specifies whether the matched URI should be included or excluded from the application’s content.

There are several ways to specify a URI match: an exact hostname, a hostname for which a URI with any subdomain of that hostname is included or excluded, an exact URI, an exact URI that can contain a query property, a partial path and use a wildcard to indicate a particular file extension


<ApplicationContentUris>
<Rule Type=”includeMatch=”http://www.example.com/”/>
<Rule type=”excludeMatch=”http://www.example.com/downloads/”/>
<Rule Type=”excludeMatch=”*.pdf/>
</ApplicationContentUris>

You can also add a content URI using the package manifest designer in Microsoft Visual Studio 2010 (the Content URIs tab). When you include a URI in your app's content, it can access your system's geolocation and media capture devices, as well as the clipboard (if your application has permission to access this functionality). It can also download files. Downloading an unknown file (such as a pdf file that cannot be handled by the application) redirects the user to the browser. Pages contained in your app's package are in the local context, and pages not included in your package (but included in your app's ApplicationContentUriRules) are in the web context.

Navigating from local to web context pages

Even if a page is in your web context, you can't navigate from a web context page back to a local context page unless you call the msWWA.addPublicLocalApplicationUri from a local context page and pass it the URI of the page that you want web context pages to be able to navigate to.


msWWA.addPublicLocalApplicationUri("ms-wwa:///page2.html");

You have to call this method once for each local context page that you want to be accessible to web context pages.

Local context pages and scripts have access to different features than pages and scripts in the web context. They can access the Windows Runtime and perform cross-domain XHR requests, for example. Both local and web context pages can access the Windows Library for JavaScript. A page not included in your app's package or included by your ApplicationContentUriRules cannot be navigated to by your app; it will open in the external browser instead.

Navigation models: multi-page and single-page

Nearly every website provides some form of navigation, usually in the form of hyperlinks that you click to go to a different page. Each page has its own set of JavaScript functions and data, a new set of HTML to display, style information, and so on. This navigation model is known as multi-page navigation.

Another navigation model is single-page navigation, where you use a single page for your app and load additional data into that page as needed. You still split your application into multiple files, but instead of moving from page to page, your app loads other documents (using an iframe) or fragments of documents (using the WinJS.UI.Fragments functions) into the main page. Because your app's main page is never unloaded, your scripts are never unloaded, which makes it easier to manage state, transitions, or animations. We recommend that Metro style apps using JavaScript use the single-page navigation model.

fragment is HTML code defined in a separate file that you load and display in host page. Unlike an iframe, which isolates the document it contains, a fragment becomes a part of the DOM of the host page when you load it. That means that fragment has access to all the same scripts and styles as the host page, and can better participate in the host page's layout. Fragments also load and run faster than content in an iframe. For Metro style apps using JavaScript, we recommend using fragments to implement the single-page navigation model. The Windows Library for JavaScript provides several functions that help you use fragments.

To load and display a fragment, you use the WinJS.UI.Fragments.clone function to create a copy of the fragment; then you add it to the host document by adding the fragment to a container element, usually by setting the contain element's innerHTML property. This adds the fragment to the host document's DOM. After your fragment is loaded into the DOM, notify the fragment so that it can perform any necessary initialization work, such as creating controls or loading data. You can provide this notification by using the WinJS.Application.queueEvent method to fire a custom event.


function loadPage(location, state) {
WinJS.UI.Fragments.clone(location, state).then(function (frag) {

var content = document.getElementById("content");
content.innerHTML = "";
content.appendChild(frag);

WinJS.Application.queueEvent({
type: "fragmentappended", location: location, fragment: content, state: state
});
});
}

Load your fragment in your startup code when main page is ready. This example uses the onmainwindowactivated event, but you could also use the DOMContentLoaded or WinJS.Utilities.ready events to run your startup code.

//default.js
WinJS.Application.onmainwindowactivated = function (e) {
if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {

loadPage("/fragments/fragment1.html");

}
}

A fragment can be as simple as a single HTML file, or it can have its own accompanying script and CSS files. Microsoft Visual Studio 11 Express for Windows Developer Preview makes it easy to add new fragments to your app (Add > New Item... > HTML Fragment). Visual Studio creates three files: fragment1.html, fragment1.js, and fragment1.css.

As you can see, your fragment looks similar to your other HTML files. It contains references to all of the same Windows Library for JavaScript files you reference in your main page ("default.html" in this example). This isn’t necessary, because by the time this fragment is loaded, the main page has already loaded Windows Library for JavaScript and made it available to your fragment. Fortunately, the fragment loader will make sure that any script or style file you reference using the same file name won’t be loaded into your app’s script context more than once, so there’s no harm in these references, and leaving them in makes it easier to edit the fragment independently.

Adding type="ms-deferred/javascript" to each of the script elements helps the fragment loaded avoid using your JavaScript more than once. This setting is ignored when your fragment is loaded as an independent page. As a general rule, if you're writing a fragment, add type="ms-deferred/javascript" to all of your script references. If you reference a CSS file that wasn't loaded by the main page, it will be loaded, potentially overriding other styles with the same name. For example, if the main page loads the light style sheet, ui-light.css, and a fragment references the dark style sheet, ui-dark.css, the main page will switch to the dark style sheet when you load the fragment.

Executing code and using WinJS controls in your fragment

Instead of using the DOMContentLoaded event to initialize your page, you should use a custom event. You wrote code that fires a custom event when the fragment is loaded. In your fragment's JavaScript file, add code that listens for that event.


(function () {
'use strict';

WinJS.Application.addEventListener('fragmentappended', function handler(e) {
if (e.location.indexOf('fragment1.html') !== -1) { fragmentLoaded(e.fragment, e.state); }
});

function fragmentLoaded(elements, options) {
WinJS.UI.processAll(elements)
.then(function () {

WinJS.UI.processAll(elements);
});
}

WinJS.Namespace.define('fragment1', {
fragmentLoaded: fragmentLoaded,
});
})();

Since the event handler will be called for every fragment that’s loaded, and since this code will not be unloaded for the lifetime of the application, make sure the specified location matches the current fragment’s location so you don’t attempt to initialize this fragment when another fragment is loaded. Because it's possible to copy a fragment into a given document more than once, it's a good idea to use classes to identify elements rather than IDs.

<div class="myRatingControl" data-win-control="WinJS.UI.Rating" />

To retrieve an element by its class name, use the querySelector method.

var ratingControlHost = elements.querySelector(".myRatingControl");
var ratingControl = WinJS.UI.getControl(ratingControlHost);
ratingControl.averageRating = 4;

The WinJS.Navigation namespace provides several functions for tracking navigation history and state: WinJS.Navigation.navigate, WinJS.Navigation.back, WinJS.Navigation.forward

You want to change the default hyperlink behavior so that, when the user clicks on a link, the app loads the link target as a fragment rather than navigating to that page. To do this, handle the hyperlink's click event and use the event to stop the hyperlink's default navigation behavior, and then call the WinJS.Navigation.navigate function and pass it the link target.


function linkClickEventHandler(eventInfo) {
eventInfo.preventDefault();
var link = eventInfo.target;
WinJS.Navigation.navigate(link.href);
}

WinJS.Application.onmainwindowactivated = function (e) {
if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {

loadPage("/fragments/fragment1.html");

WinJS.Utilities.query("a").listen("click", linkClickEventHandler);

}
}

Create an event handler for the navigated event. This event is raised when you call WinJS.Navigation.navigate, WinJS.Navigation.back, or WinJS.Navigation.forward.

function navigatedEventHandler(eventInfo) {

// Retrieve the content host and clear its contents.
var content = document.getElementById("content");
content.innerHTML = "";

// Call your fragment loading function.
loadPage(eventInfo.detail.location, eventInfo.detail.state);

}

WinJS.Application.onmainwindowactivated = function (e) {
if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {

WinJS.Utilities.query("a").listen("click", linkClickEventHandler);
WinJS.Navigation.addEventListener("navigated", navigatedEventHandler);

// Load the first page.
WinJS.Navigation.navigate("/fragments/fragment1.html");

}
}

When you use the WinJS.Navigation.navigate method to navigate, it stores the navigation history for you. You can use this navigation history to navigate backwards and forwards.

function backButtonClickEventHandler(e) {
if (WinJS.Navigation.canGoBack) {
WinJS.Navigation.back();
}
}

document.getElementById("backButton").addEventListener("click", backButtonClickEventHandler);

var backButton = document.getElementById("backButton");

if(WinJS.Navigation.canGoBack){

backButton.disabled = false;
}
else {

backButton.disabled = true;
}

When your app encounters a navigation error when navigating between top-level documents or inside an iframe, it checks the root of its package for a file called wwa-error.html; if the file isn't present, it displays a default error message instead. By creating a wwa-error.html page, you can customize the message you deliver to your app's users.

wwa-error.html, wwa-error.js


<button id="backButton" class="win-backbutton"></button>

document.addEventListener("DOMContentLoaded", initialize, false);

function initialize() {

var backButton = id("backButton");
if (top === self) {
backButton.addEventListener("click", function () { history.go(-1); }, false);
} else {
backButton.style.display = "none";
}
}

Parse the query string. You can find it by calling window.location.search.substring(1). The query string returned by this call has the following syntax: httpStatus=status&failureUrl=failureUrl

If the failure doesn't have a http status code, the query string looks like this: failureName=failureName&failureUrl=failureUrl


function getQueryParameter(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] === variable) {
return pair[1];
}
}
return "";
}

A mashup is a web application that uses data from two or more sources to create something new.

The target Uri for an XHR request is not restricted by the ApplicationContentUriRules listed in the manifest.

The "ms-https-connections-only" meta element value enables you to specify that your Metro style app using JavaScript app should not use HTTP connections for navigations or other non-media web content retrievals. This meta tag must exist in the head of the your app's start-page HTML document and must exist at the time that the document fires its load event. This is the only time this feature may be turned on and once set, it remains in effect until the next time our app is started. Note that this means that iframe elements in your start page that point to HTTP URIs may load if the iframe exists and begins to load before the document finishes loading.

Brak komentarzy: