Using jQuery with Windows 8 Metro JavaScript App causes security error
Asked Answered
L

11

44

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?

Loferski answered 2/6, 2012 at 3:16 Comment(6)
Are you loading jquery via a cdn?Phiphenomenon
No. This is an error triggered within the local jQuery code's execution.Loferski
On a side note, it looks like I can learn a new promise system instead of jQuery's $.Deferred.Loferski
jQuery 1.8 requires two more modifications in order to work together with Windows 8 flawlessly. I've written up a Blogpost that covers the necessary changes, gives some background information and provides a "patched" version of jQuery 1.8.Hogle
Here's a good resource for using jQuery on Windows 8: incloud.de/2012/08/windows-8-using-jquery-for-app-developmentTracee
Use following to solve this problem: github.com/Microsoft/winstore-jscompatIssi
P
33

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.

Phonic answered 2/6, 2012 at 12:46 Comment(9)
Awesome, this was bugging me as well and the fix worked perfectly. In case someone can't be bothered doing this or doesn't want to mess with jQuery source, this is a minified version I just created for myself: pastebin.com/0NC6XBFp.Bartolemo
Just as a data point, jQuery 1.7.1 doesn't cause this error, it's new with something that changed in 1.7.2.Scent
That certainly explains all the blog posts about using jQuery with Metro with no one having issues. They were mostly written when VS12 was in dev preview (released 16 September 2011), prior to jQuery 1.7.2 (released 21 March 2012).Loferski
Weird - I just tried with the new Release Preview version of Win8 and jQuery 1.7.2, and everything just worked, no security error. Something odd's going on here...Scent
Adam, are you getting a first chance exception or an unhandled exception? If you hit "continue" on the dialog from the debugger, does the app die or continue to run? If it continues to run, it's not actually a problem, it's just a handled exception. If the app dies, then something else is going on.Scent
I'm getting this with both jQuery 1.7.1 and 1.7.2 (minified) with VS2012RC. I don't even have to use jQuery anywhere to see the error. It shows up in the JavaScript Console just by including script src=jquery in default.html.Usquebaugh
When using jQuery 1.8, you need to apply changes to two other parts of jQuery, see my response here: https://mcmap.net/q/377029/-using-jquery-with-windows-8-metro-javascript-app-causes-security-errorHogle
@Zac Just to let you know , you are awesome.Warchaw
Is this fix still required in the 2.0+ release of jQuery?Sheerlegs
E
8

Here is your answer

https://github.com/appendto/jquery-win8

Its official jquery library for windows 8

Entomo answered 13/11, 2012 at 14:26 Comment(3)
The project is "terminated" because its authors say the problem was fixed by jQuery 2.0; however the problem still occurs with jQuery 2.1.0 and VisualStudio 2013...Orangeman
In fact the problem does not occur with jQuery 2.0.2 so there seems to be a regression between 2.0.2 and 2.1.0Orangeman
The problem does persist in jQuery 2.2.4 and 3.1.0, no append() operations are possible on WP8 apps.Arjun
P
7

For what it's worth, I've ported the majority of jQuery core to wrap the native WinJS library. It's lightweight and provides just about everything that jQuery does with the addition of some plugins for badges, notifications, etc.

It is a work in progress, but I'm trying to get some people to join in the fun.

https://github.com/rmcvey/winjq

Quick write-up (documentation is being added to): http://practicaljs.com/jquery-in-windows-8-apps/

Prologize answered 31/8, 2012 at 17:44 Comment(2)
Great library, hope you keep it up :)Krell
Yes, I used it for the Answers.com Windows 8 app; are you having specific issues with the library?Prologize
S
7

After the recent //Build/ 2012 conference and this talk talks about using jQuery in Windows 8 Store Apps. Specifically, they talk about the exact exception of script injection inside innerHTML, and talk about the updates done in this.

The company AppendTo also officially unveiled jQuery for Windows 8 during that talk. It looks neat from the demonstration given in the talk in the link about.

They also say that it is not a good idea to get jQuery from CDN for Windows 8 Apps in Local Context!

Shylashylock answered 7/11, 2012 at 4:31 Comment(1)
Exactly -- jQuery from CDN will not work, as it throws an error. You'll need to download the latest cersion and store it locally for your project.Sheerlegs
L
6

The JavaScript Dynamic Content shim on GitHub was created and released by Microsoft Open Technologies to address this error. It has not been tested with jQuery but will most likely solve your problem. Reference the winstore-jscompat.js file in the beginning of your app before any other scripts are run and you should no longer see this error.

Layard answered 19/8, 2014 at 18:38 Comment(2)
Thanks. This works properly with AngularJS, so I assume it will also work with jQuery.Fellah
Thanks!! I would vote up your answer 10 times if I could, this really is the final solution to the Windows problem. Now I can use jQuery 2.x normally. I wasted hours looking around for a solution, thank you. I'll vote you up everything now.Arjun
S
2

I've done a little more investigation, and wanted to clarify a couple of things.

The error you see is in the JavaScript console, not an actual exception. The jQuery code continues to run just fine. It's actually something the underlying system is logging, not an error or exception.

There's no reason to patch jQuery or do anything else - it's a noisy system component, not an actual error.

Scent answered 12/6, 2012 at 19:54 Comment(3)
My app force closes when trying to ignore this error message.Braeunig
Where are you seeing this - do you get it when first loading the jquery .js file, or is it as a result of something you're actually doing?Scent
My app works fine with the "noise", but I wonder if this will get your app rejected from the Windows 8 app store by the code reviewers.Urbana
S
1

I wrote a pretty detailed explanation on how to get jQuery to work with Windows 8 here http://davidvoyles.wordpress.com/2013/09/23/hacking-jquery-to-work-in-windows-8/

Sheerlegs answered 23/9, 2013 at 20:56 Comment(1)
I moved my site a while ago, I guess it broke the link. Here is the new one: davevoyles.azurewebsites.net/…Sheerlegs
F
0

If you still need it, I am writting a reimplementation of the Deferred object found in jQuery.

Once finished it should be 100% compatible with jQuery's Deferred object. Right now it's quite complete but needs some testing.

See this.

Hope this will help!

That said, I think it should be a good idea to learn how to use Microsoft's implementation of Promise instead of jQuery when working on Windows 8 apps.

Fanion answered 15/6, 2012 at 13:49 Comment(0)
A
0

I was able to eliminate the problem by finding all places in jQuery that set innerHTML and wrapping the value being set with toStaticHTML().

So, for example:

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

became:

div.innerHTML = toStaticHTML("   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>");

To be safe, I've also defined this just before jQuery is defined, in case the file is used in a normal browser:

window.toStaticHTML = window.toStaticHTML || function (s) { return s; };

To me that seemed to be the safest change, although it required patching a dozen places in jQuery. (don't use a var statement before the toStaticHTML)

Alienor answered 10/8, 2012 at 22:5 Comment(2)
Careful with this approach as toStaticHTML may radically change your string. For instance, in the first example, though you began with a <link/> tag, after the pass through toStaticHTML, you won't have that anymore. Other things that are removed include HTML5 data-attributes.Starla
Agreed. We tried this approach. but it stripped all of the data from the tags we were trying to pass. Useless.Sheerlegs
C
0

I believe this is the same restriction as imposed by Content Security Policy (CSP). That specific case was addressed in jQuery 1.8.0. Does the problem still occur there?

https://github.com/jquery/jquery/commit/dc83072878ed9636c8158a014bd9fa4acc1ccce3

Chlori answered 11/8, 2012 at 1:53 Comment(2)
Yes the problem still occurs with VisualStudio 13 and jQuery 2.1.0Orangeman
Have you reported it to bugs.jquery.com? Be sure to post a clear explanation of the problem you are seeing and not just a pointer back to this page, since it is old and referring to an old problem.Chlori
G
0

jQuery itself did not throw such exceptions for me in the latest version as long as I replaced all code of the form e.g.:

$('<input type="button" value="Press Me" />')

with

$(toStaticHTML('<input type="button" value="Press Me" />'))

Note that not all HTML strings are considered unsafe e.g.:

$('<span></span>')

Does not throw any exceptions. However jQuery still throws exceptions on append if you do something of the sort:

var div = '<div class="' + classesToApply + '"';
div += attrToAdd;
div += '</div>';

$(div).appendTo(container);

The above is not an example for good practices using jQuery still some people do it so you may encounter the error. Notice the above code does not generate the same error as the very first snippet but instead throws the error inside jQuery.append. This error is still fixed via performing $(toStaticHTML(div)).appendTo(container);

Guitarfish answered 20/8, 2012 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.