Using jQuery with Windows 8 Metro JavaScript App causes security error

patridge picture patridge · Jun 2, 2012 · Viewed 32.5k times · Source

Since it sounded like jQuery was an option for Metro JavaScript apps, I was starting to look forward to Windows 8 dev. I installed Visual Studio 2012 Express RC and started a new project (both empty and grid templates have the same problem).

I made a local copy of jQuery 1.7.2 and added it as a script reference.

<!-- SomeTestApp references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/jquery-1.7.2.js"></script>
<script src="/js/default.js"></script>

Unfortunately, as soon as I ran the resulting app it tosses out a console error:

HTML1701: Unable to add dynamic content ' a' A script attempted to inject dynamic content, or elements previously modified dynamically, that might be unsafe. For example, using the innerHTML property to add script or malformed HTML will generate this exception. Use the toStaticHTML method to filter dynamic content, or explicitly create elements and attributes with a method such as createElement. For more information, see http://go.microsoft.com/fwlink/?LinkID=247104.

I slapped a breakpoint in a non-minified version of jQuery and found the offending line:

div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";

Apparently, the security model for Metro apps forbids creating elements this way. This error doesn't cause any immediate issues for the user, but given its location, I am worried it will cause capability-discovery tests in jQuery to fail that shouldn't.

I definitely want jQuery $.Deferred for making just about everything easier. I would prefer to be able to use the selector engine and event handling systems, but I would live without them if I had to.

How does one get the latest jQuery to play nicely with Metro development?

Answer

Adam Freeman picture Adam Freeman · Jun 2, 2012

You need to edit the jQuery source so that you pass the jQuery.support function to MSApp.execUnsafeLocalFunction, which disables the unsafe content checking, like this:

jQuery.support = MSApp.execUnsafeLocalFunction(function() {

    var support,
        all,
        a,
        select,
        opt,
        input,
        fragment,
        tds,
        events,
        eventName,
        i,
        isSupported,
        div = document.createElement( "div" ),
        documentElement = document.documentElement;


    // lots of statements removed for brevity

    return support;
});

You need to remember to remove the last pair of parenthesis - you don't need a self-executing function because execUnsafeLocalFunction automatically executes the function it is passed.

I suggest that a better approach is to use the WinJS features - this includes the WinJS.Promise object as an alternative to deferred operations (which are themselves an implementation of the Promise pattern). And you can do some basic DOM manipulation using the WinJS.Utilities namespace.

You should think twice about using jQuery for deferred operations. The WinJS.Promise object is used throughout the Metro APIs to represent async activities and you will end up using two similar-but-different approaches.