Navigating to Content in Any Location
During the “Creating a Navigation App Project” section of this hour, we talked about the navigation model used in the last three project templates (Navigation, Split, and Grid). There we covered loading content (page controls) within our application. But sometimes we need to load content from the web.
Understanding the App Host
Before we dig deeper into loading content, we need to understand how the App Host works. The App Host does what the name implies: It hosts apps written in JavaScript, HTML, and CSS. When developing an app using these technologies, we need the app to run in a container. Languages such as C++, C#, and Visual Basic each compile into an executable that the operating system can call directly. For our apps, we have only text files. In the web world, the web browser processes these files to display content to the user. In much the same way, the App Host process (wwahost.exe) hosts and executes JavaScript Windows Store apps. The App Host provides security contexts that the code can run in. Page controls that we create and reside in the app run in local context; resources outside the app run in what is called the web context.
Context is an important concept in Windows Store apps written in JavaScript. If we are bringing dynamic content into our app from the web, we need to make sure that the content isn’t allowed to inject JavaScript and start taking over our process. We talk about some ways to keep apps secure during Hour 7. For now, it is important to know that we need to take precautions when loading dynamic remote data. Of course, sometimes we want to call a remote page that we are in control of. For example, we might want our app to access a web service that we created in the cloud, to obtain data.
Running in Local Context
When our app is running in local context, we have access to the entire Windows Runtime and Windows Library for JavaScript. Apps run in local context when pages are loaded from within the app package. This means apps have access to the machine and hardware sensors, such as the GPS and web camera.
However, when we run JavaScript in the local context, the actual .js file must exist locally. We cannot use remote source references inside the local context. The following is not allowed in the local context:
<
script
src
="http://www.somesite.com/somescript.js"></
script
>
The protocol when using local context resources is ms-appx://. To access a local resource in our app, we would use ms-appx://ourpackage/someresource. We can use a shortcut by using three forward slashes and just set it to ms-appx:///someresouce. Using this protocol, we load content packaged in our app into the local context. This code has access to the Windows Runtime and all of the device’s hardware capabilities.
Inside the local context, any HTML that is injected into an app needs to be filtered by the window.toStaticHTML method, for security reasons. The local context allows the application to talk with the operating system and run with more privileges than a typical web browsing session. Because injecting HTML is a security risk, Windows runs any calls to innerHTML (and related operations) through a filtering process invoked by toStaticHTML. toStaticHTML simply walks through the data it is passed and strips out anything that resembles a script, while keeping the static HTML tags (like <b>) intact. If toStaticHTML is not called and script is present, an exception is thrown.
In some scenarios, injecting HTML and JavaScript into the DOM is valuable. It isn’t allowed by default, but we can override that if we need to by calling MSApp.execUnsafeLocalFunction. Do this with great caution, however, and never use it on content that isn’t validated. We talk more about this function in Hour 7.
Running in Web Context
If we load content from the web, those pages are run in the web context. If we just link to content on the web, Windows opens the web browser and our app goes to the background. We cannot have a top-level navigation to web content. If we want to actually display the web content inside the app, we use an iframe. This way, the web resource that is loaded will function just it does in the browser. But it doesn’t have access to the user’s data, device hardware, or any of the Windows Runtime.
If we are trying to display unknown content, loading the iframe with the sandbox attribute set is best. By default, the iframe lets all scripts and form elements run and also gets information about the origin that could lead to accessing data such as cookie information. If we are loading our own resource on our web server or a well-known resource and we need the script or the form data to be processed as normal, we just pull it in with an iframe. However, if we are bringing up content that we don’t know about—perhaps something the user has been able to browse to—we want to make sure we put the iframe in sandbox mode. We have the option to tell it to execute scripts but not forms, or vice versa. We can let it access the origin information (which allows sharing local storage such as cookies) or keep it from doing so.
Using Third-Party Libraries
If we needed to include a third-party library, we could bring the entire JavaScript file down locally so that it is included in our app package. We could then look at the code and make sure it isn’t doing anything malicious. If it is local, we can use it normally as long as the library isn’t trying to update the DOM. Remember, the local context filters any calls to innerHTML, outerHTML, pasteHTML, document.write, and functions like them. So if a third-party library will be injecting HTML and script into the DOM, it will not work even if the library is included with the app. We can get a third-party library that modifies the DOM to work in Windows Store apps in two ways. One way is to load the content in an iframe via the ms-appx-web:// protocol and load the script remotely. This lets it run in the web context, which means it can manipulate the DOM all it wants. However, it will not be able to use the Windows Runtime and other features that are available to only the local context. The second way we can get the third-party library that manipulates the DOM to work correctly is to modify the script and wrap the function(s) that manipulate the DOM in the MSApp.execUnsafeLocalFunction. Again, that call should be used only on scripts that are absolutely trusted and sanitized.
We don’t discuss any third-party libraries in this book because we don’t even enough pages to cover all the built-in functionality Microsoft provide, much less those provided by third-party libraries. However, Windows Store apps can definitely use third-party libraries.
Communicating Between Local Context and Web Context
Local context and web context can talk to each other by passing data through the postMessage function. This is a standards function that allows each iframe to share data at will. To use this function, we need to add an event listener for the window (not document) message event. Inside the event handler, we get the data being communicated in the event.data property (where event is the parameter of the event handler). For example:
window.
addEventListener(
"message"
,
function
(
evt) {
var
msg=
evt.
data;
}
The code to kick off that event looks similar to the following:
window.
parent.
window.
postMessage(
data,
target);
The idea is that this code is in an iframe and it is trying to send a message to the main default.html where it is hosted. It finds its parent window.parent and then calls its parent’s window.postMessage function. We cover this scenario in detail when we discuss how to work with passing messages between iframe elements securely during Hour 7.