Opened 7 years ago

Closed 4 years ago

#16432 closed defect (fixed)

[meta] support Windows 8 Metro JavaScript App platform

Reported by: Paul Christopher Owned by: dylan
Priority: low Milestone: 1.11
Component: Dijit Version: 1.8.1
Keywords: metro Cc: Douglas Hays, Adam Peller, cjolif, Sebastien Pereira
Blocked By: Blocking:

Description (last modified by bill)

Description

Since Windows 8 supports app development using the standard web techniques, Dojo immediately suggests itself - especially since the framework already supports app development using dojox/mobile. But because Microsoft has integrated a new security model in Windows 8, Dojo cannot be used without problems. E.g. trying to create a dijit/form/DateTextBox fails with the error

Unable to add dynamic content "<input type='hidden' name="date1"/>". 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.

Steps to reproduce the issue

  • Create a "Hello World" app as described in detail here: http://msdn.microsoft.com/library/windows/apps/hh986964.aspx
  • Replace default.html and default.js with the attached test case.
  • Run the app. This works. Now uncomment in default.html the code part containing the DateTextBox. Rerun the app. This triggers the above error message.

Related tickets

http://bugs.dojotoolkit.org/ticket/15530

Additional material

Discussions on jQuery and Win8

Materials on Microsoft's security model:

Discussion

This is a blocker for me at the moment. Is there any simple workaround for that? I would like to developp an app using Javascript because I want to target different platforms at the same time: Win8 tabelts, iPads, Android tablets.

Attachments (1)

TestCase.zip (1.5 KB) - added by Paul Christopher 7 years ago.

Download all attachments as: .zip

Change History (47)

Changed 7 years ago by Paul Christopher

Attachment: TestCase.zip added

comment:1 Changed 7 years ago by bill

I'm just confused. Our automated tests seemed to run fine on Windows 8 / IE10. Do you know what the difference is?

comment:2 Changed 7 years ago by Paul Christopher

The difference is when writting an app, that the app runs in a so called "local context" and not in a "web context" (that is a browser), see this talk on how jQuery was made compatible with Win8: http://channel9.msdn.com/Events/Build/2012/3-130.

MappedTextBox creates a hidden input field with a name attribute and injects this node with myNode.innerHTML = .... However, this is not allowed in the local security systems, see this link: http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx. At least, this is my explanation for the error.

There might be even more problems in Win8 apps, e.g. with dojo/request and JSONP: The new security model does not allow to insert script tags to external ressources - but inserting script tags is the prerequisit of JSONP, isn't it? But that is all described in the above talk...

I think, there is a need to pull in all the dojo test in the "locale context" (and not the browser context only like IE10 and Win8) and rerun the test there. At least that's what the jQuery people did (again see above talk).

comment:3 Changed 7 years ago by bill

Ah I see, Metro sounds like PhoneGap or Adobe Air. Also sounds like an interesting challenge for dijit.

Even if we got rid of the MappedTextBox mixin, I don't see why you wouldn't get a failure just by the fact that DateTextBox, and most other widgets, use templates. But apparently you don't, since execution got past that point.

I also note that eventually what's failing isn't foo.innerHTML = bar, but rather parent.appendChild(node).

comment:4 Changed 7 years ago by bill

Description: modified (diff)

comment:5 Changed 7 years ago by Paul Christopher

I could get rid off the above error by wrapping all innerHTML calls in dojo/dom-construct's toDom method inside MSApp.execUnsafeLocalFunction(function () { }) as described here http://msdn.microsoft.com/library/windows/apps/hh767331.aspx

if(match && tagWrap[tag]){
    wrap = tagWrap[tag];
    MSApp.execUnsafeLocalFunction(function () {
        master.innerHTML = wrap.pre + frag + wrap.post;
    });
    for(i = wrap.length; i; --i){
	master = master.firstChild;
    }
}else{
    MSApp.execUnsafeLocalFunction(function () {
        master.innerHTML = frag;
    });
}

However the parser still fails with a TypeError and that a certain property "replace" cannot be called because the object is null or undefined.

comment:6 Changed 7 years ago by bill

Cc: Douglas Hays added

I could get rid off the above error by wrapping all innerHTML calls in dojo/dom-construct's toDom method inside MSApp.execUnsafeLocalFunction(function () { })

Agreed, I think execUnsafeLocalFunction() can get around any of these exceptions, although ideally I'd like to only use it as a last resort.

MappedTextBox creates a hidden input field with a name attribute and injects this node with myNode.innerHTML = .... However, this is not allowed in the local security systems, see this link: http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx.

Agreed. And, for widgets that *don't* extend MappedTextBox, the template creates a node with an <input name="...">. See for example the ${!nameAttrSetting} in the TextBox template. So in either case, Metro will complain because we are using innerHTML to set that "name" attribute.

The irony is that we are setting the "name" attribute through innerHTML, rather than saying node.setAttribute("name", ...), to workaround bugs in old versions of IE (IE6 and IE7 IIRC).

If not for that IE6-7 workaround, we could probably get around the exception by making MappedTextBox use domConstruct.create() instead of domConstruct.place(), and by setting the name using setAttribute() for non MappedTextBox widgets like the plain TextBox.

So in conclusion, I agree that using execUnsafeLocalFunction() is a practical workaround for these innerHTML errors.


PS: I don't know why you get that replace error with the parser, I'll check it out later.

comment:7 Changed 7 years ago by bill

PPS: Out of curiosity, why are you [trying to] use the Windows 8 Metro JavaScript App framework rather than Cordova or Adobe Air?

Last edited 7 years ago by bill (previous) (diff)

comment:8 in reply to:  7 Changed 7 years ago by Paul Christopher

Replying to bill:

PPS: Out of curiosity, why are you [trying to] use the Windows 8 Metro JavaScript App framework rather than Cordova or Adobe Air?

Phonegap/Cordova and Adobe Air do not support the development of Win8 apps - as far as I can see. I can use Dojo therefore to create apps for the iPad and Android tablets. I cannot use Dojo at the moment to create apps for Microsoft's Surface tablet - and I personally think that Microsoft will soon become an important player in the tablet market. The real power of developping apps in JavaScript is that you can port parts of the code easily to the different platforms. That is at least what I am trying to investigate: How easy is it to write one app for all three platforms with Dojo. How much code is reusable, how much code must be changed? Can those parts which are platform agnostics isolated in separate modules? etc.

PS: I don't know why you get that replace error with the parser, I'll check it out later.

After a long time of debugging I noticed that Dojo fails in locale.js. If you set the locale='de' and try to instantiate a DateTextBox like this

<input type="text" name="date1" id="date1" data-dojo-type="dijit/form/DateTextBox" />

Dojo fails in dojo/locale line 509 inside the _processPattern method because "pattern" is undefined:

var chunks = pattern.match(/(''|[^'])+/g)

I think the real error happens much earlier inside the _parseInfo method. There "bundle" is empty and "datePattern" is undefined, maybe because getGregorianBundle failed to load the required resources? But why? An issue with the AMD loader?

P.S.: The above replace error also happend in locale.js but somewhere else (because in my earlier test case I gave the DateTextBox an initial value (replace error)). With no initial value specified, you get a match error as described above.

comment:9 Changed 7 years ago by Paul Christopher

And I try to use Dojo for Win8 app development since this official Microsoft book http://blogs.msdn.com/b/microsoft_press/archive/2012/08/20/free-ebook-programming-windows-8-apps-with-html-css-and-javascript-second-preview.aspx tells me that I can use it, see page 23 ;-))

"However, apps can freely use third-party libraries by bringing them into their own app package, provided of course that the libraries use only the APIs available to WinRT apps. For example, apps written in JavaScript can certainly use jQuery, Modernizer, Dojo, prototype.js, Box2D, and others, with the caveat that some functionality, especially UI and script injection, might not be supported." (Programming Windows 8 Apps, page 23)

comment:10 Changed 7 years ago by Paul Christopher

A remark on dojo/sniff and how to detect whether you are running inside a browser or the so called WWAHost.exe (in case of a metro app): I think each metro app has a global object called "Windows" [not window]. Most apps do include WinJS by default. So most apps have a global "WinJS" object, too. But there seems to be no way to get the version number of the OS at the moment, see http://stackoverflow.com/questions/10125324/get-os-version-in-winrt-metro-app-c-sharp

comment:11 Changed 7 years ago by bill

A remark on dojo/sniff and how to detect whether you are running inside a browser or the so called WWAHost.exe (in case of a metro app): I think each metro app has a global object called "Windows" [not window]

Makes sense. And what is this new environment called anyway? "Win8" seems a bit vague since IE10 also runs on Windows 8. has("win8app") maybe? Seems like there should be some official name.

There might be even more problems in Win8 apps, e.g. with dojo/request and JSONP: The new security model does not allow to insert script tags to external ressources - but inserting script tags is the prerequisit of JSONP, isn't it?

Yes, but remember that dojo/request is setup to have various drivers (aka plugins) for different methods of communication, like XHR and iframes. Albeit, there's no plugin that works over XHR but expects a JSONP-ish response from the server.

PS: Hmm, maybe there isn't a problem after all. I just looked at dojo/request/script.js, and although it does create <script> nodes, it uses createElement() and appendChild(), not innerHTML or document.write(). So, not sure if Microsoft's environment will flag that or not.

Last edited 7 years ago by bill (previous) (diff)

comment:12 Changed 7 years ago by bill

About creating the app: how did you get dojo and dijit into the app? I can see how to add a single file, but not a whole directory.

comment:13 in reply to:  12 Changed 7 years ago by Paul Christopher

Replying to bill:

About creating the app: how did you get dojo and dijit into the app? I can see how to add a single file, but not a whole directory.

I just open a new Explorer window and copy the dojo folders to the clipboard (right click -> copy). Then switch to Visual Studio. On the left hand side, where all the files of the project are shown, right click on the project name and choose "paste". But you can also copy the files with the Explorer in the right place. In the icon bar on top of Visual Studio's project files pane at the right hand side of the screen, there is also an icon called "Show all files". Show them. After that select the grayed out folders, right click, and choose "Add to project". You can run the app by hitting F5.

Makes sense. And what is this new environment called anyway? "Win8" seems a bit vague since IE10 also runs on Windows 8. has("win8app") maybe? Seems like there should be some official name.

Don' know. In the video link above, the Microsoft guy was just taking about browser vs. WWAHost.exe (whereas both use Trident as rendering engine).

comment:14 Changed 7 years ago by Paul Christopher

When trying to load the dojo/cldr/nls/en/gregorian bundle, a "/x" is added to the mid path by dojo.js toURL method. So the new mid path in dojo.js getModuleInfo is "dojo/cldr/nls/en/gregorian.js/x". Maybe that is the cause, why the instantiation of the DateTextBox fails...

comment:15 Changed 7 years ago by Adam Peller

Cc: Adam Peller added

comment:16 in reply to:  14 Changed 7 years ago by bill

(edited reply based on further research)

Replying to Paul Christopher:

When trying to load the dojo/cldr/nls/en/gregorian bundle, a "/x" is added to the mid path by dojo.js toURL method. So the new mid path in dojo.js getModuleInfo is "dojo/cldr/nls/en/gregorian.js/x". Maybe that is the cause, why the instantiation of the DateTextBox fails...

Hmm, well there definitely seems to be a problem loading the NLS resources. I did see that /x thing but it might be a red herring.

Before loading a language/locale specific module like dojo/cldr/nls/en/gregorian, the i18n code loads the root file, dojo/cldr/nls/gregorian, in order to find out what language/locale specific modules exist.

injectUrl() tries to load dojo/cldr/nls/gregorian by inserting this into the document:

<script src="/js/dojo/cldr/nls/gregorian.js" type="text/javascript"></script>

Then def() gets called, but with the contents of cldr/nls/en/gregorian.js.

This is easy to see in the debugger by setting a breakpoint in the def() method, and then looking up the call stack to the function that called def(), listed as "gregorian.js [dynamic]".

From there problems start to happen because root.root is undefined for the English version of gregorian.js.

Last edited 7 years ago by bill (previous) (diff)

comment:17 Changed 7 years ago by bill

PS: I updated my comment above after some more research. I tried making Windows8 apps follow the same code path as modern browsers, rather than the IE6-9 code path, by updating the feature test as:

has.add("ie-event-behavior", !!doc.attachEvent && typeof Windows === "undefined" &&
	(typeof opera === "undefined" || opera.toString() != "[object Opera]"));

But still the same problem. It's very strange, seems like dojo/cldr/nls/en/gregorian is getting loaded even though no one asked for it.

PPS: Oh, looks like it's from http://msdn.microsoft.com/en-us/Library/Windows/Apps/hh965372.aspx

Last edited 7 years ago by bill (previous) (diff)

comment:18 in reply to:  6 ; Changed 7 years ago by kbenjamin

Replying to bill:

The irony is that we are setting the "name" attribute through innerHTML, rather than saying node.setAttribute("name", ...), to workaround bugs in old versions of IE (IE6 and IE7 IIRC).

If not for that IE6-7 workaround, we could probably get around the exception by making MappedTextBox use domConstruct.create() instead of domConstruct.place(), and by setting the name using setAttribute() for non MappedTextBox widgets like the plain TextBox.

Isn't support for these older browsers to be discontinued in Dojo 2.0?

It seems like wholesale replacement of .innerHTML and like would be a possible solution.

comment:19 in reply to:  18 Changed 7 years ago by bill

Replying to kbenjamin:

Isn't support for these older browsers to be discontinued in Dojo 2.0?

Yes, our plan is to desupport IE6 & IE7 for Dojo 2.0.

It seems like wholesale replacement of .innerHTML and like would be a possible solution.

Not sure what you mean. But I'm looking at changing the main code path to work by calling node.setAttribute("name", ...), and then making the current code path run for IE only. Perhaps that's what you were getting at.

comment:20 Changed 7 years ago by Paul Christopher

I have tried to change default.js to make it more AMD like.

require([
    "dojo/ready",
    "dojo/parser",
    "dijit/registry",
    "dojo/dom",
    // non referenced includes
    "dijit/form/Button",
    "dijit/form/DateTextBox"
], function (ready, parser, registry, dom) {

    ready(function () {

        console.log('ready');

        WinJS.Binding.optimizeBindingReferences = true;

        var app = WinJS.Application;
        var activation = Windows.ApplicationModel.Activation;

        app.onactivated = function (args) {

            console.log('app.onactivated');

            if (args.detail.kind === activation.ActivationKind.launch) {
                if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                    // TODO: Diese Anwendung wurde neu eingeführt. Die Anwendung
                    // hier initialisieren.
                } else {
                    // TODO: Diese Anwendung war angehalten und wurde reaktiviert.
                    // Anwendungszustand hier wiederherstellen.
                }
                    
                registry.byId('myButton').on('click', function () {
                    dom.byId('greetingOutput').innerHTML = 'Hello ' + registry.byId('myInput').get('value') + ' !';
                });

            }
        };

        app.oncheckpoint = function (args) {
            // TODO: Diese Anwendung wird gleich angehalten. Jeden Zustand,
            // der über Anhaltevorgänge hinweg beibehalten muss, hier speichern. Dazu kann das
            // WinJS.Application.sessionState-Objekt verwendet werden, das automatisch
            // über ein Anhalten hinweg gespeichert und wiederhergestellt wird. Wenn ein asynchroner
            // Vorgang vor dem Anhalten der Anwendung abgeschlossen werden muss,
            // args.setPromise() aufrufen.
            console.log('app.oncheckpoint');
        };

        app.start();
        console.log('app.start');
    });
});

However this does not to work. The app.onactivated event gets never fired. Console output is only "ready app.start". No log for app.onactivated. I wonder if this is an issue of our loader, too or something else? I do not only ask this question for ourselves but I have also asked the Microsoft guys: http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/2790d838-ccd9-42b1-ba08-d72d4f10858e

comment:21 Changed 7 years ago by bill

Summary: Using Dojo with Windows 8 Metro JavaScript App causes security error[meta] support Windows 8 Metro JavaScript App platform

Broke off the NLS loading issue to ticket #16451, and the problem with the name attribute to #16452.

Not sure what's up with app.onactivated.

comment:22 Changed 7 years ago by Paul Christopher

Some reading what YUI did on win8 app development:

The YUI people seem to have created a new widget, a grid view, see slide 46, which replaces the native WinJS grid container. Maybe this topic on "supporting win8 app" is also a topic for the dojox/mobile team? As slide 43 says in the YUI presentation: "It's all about reusing code". Me as developper I want to become independent from WinJS and write cross-platform code for tablets with a JavaScript framework I know: Dojo. Thus for the dojox/mobile team, mimicing win8 controls could also be an interesting topic...

comment:23 Changed 7 years ago by bill

In [30154]:

Add sniff for running inside Windows 8 Store App platform. Preliminarily called "win8app". Refs #16432 !strict.

comment:24 Changed 7 years ago by bill

In [30155]:

No need for Windows 8 Store Apps to follow the IE specific code path for checking when scripts finish loading. At least according to my preliminary tests. (Likely no need for IE10 either.) Refs #16432 !strict.

Also removing Opera workaround that's no longer needed, refs #15096.

comment:25 in reply to:  23 Changed 7 years ago by Paul Christopher

Replying to bill:

In [30154]:

Add sniff for running inside Windows 8 Store App platform. Preliminarily called "win8app". Refs #16432 !strict.

Maybe it could also be called has("WWAHost")? Rational: WWAHost is the environment in which the app runs. It is based on Trident as rendering engine and Chakra as Javascript interpreter (like IE10). Unfortunatley, there seems to be no way at the moment to get the version number of the WWA host from the "Windows" object. If you have a global "Windows" object, you only know that you are running indside a WWAHost. WWA stands for Windows Web Application. Win8 has a WWAHost. Probably Win9 will also have a WWAHost (like e.g. every Windows system has an SVCHost, which is responsible for all the services).

comment:26 Changed 7 years ago by bill

Sure, maybe WMAHost is better. I also noticed that the other platform sniff tests are working off of dav/dua.

dav is "5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; MSAppHost/1.0)" and dua is "5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; MSAppHost/1.0)" so I guess either one is sufficient to get the version, although I'm not sure whether the version should be 1.0, 5.0, 10.0, or what.

Another alternative for the name (as shown above) is MSAppHost.

comment:27 in reply to:  26 Changed 7 years ago by Paul Christopher

Replying to bill:

Sure, maybe WMAHost is better. I also noticed that the other platform sniff tests are working off of dav/dua.

dav is "5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; MSAppHost/1.0)" and dua is "5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; MSAppHost/1.0)" so I guess either one is sufficient to get the version, although I'm not sure whether the version should be 1.0, 5.0, 10.0, or what.

Another alternative for the name (as shown above) is MSAppHost.

Haven't looked at other sniff tests, but you are right: It is better to use the navigator object to check whether we are running on an MSAppHost - at least you get some version numbers there ;-)

comment:28 Changed 7 years ago by Colin Snover

bill, in [30155] why are you setting a lang property in the loader?

comment:29 Changed 7 years ago by bill

Woops, thanks for catching that, I checked that in by mistake; was trying to debug #16451.

comment:30 Changed 7 years ago by bill

In [30265]:

rollback accidental change from [30155], refs #16432 !strict.

comment:31 Changed 7 years ago by bill

Priority: undecidedlow

comment:32 Changed 7 years ago by bill

Milestone: tbdfuture

comment:33 Changed 6 years ago by bill

In [30678]:

rename "win8app" to "msapp", and get version number too (currently 1.0), rather than just boolean, refs #16432

comment:34 Changed 6 years ago by bill

#15530 is a duplicate of this ticket.

comment:35 Changed 6 years ago by dylan

What's the status of this? I'm receiving more regular requests about getting Dojo working inside native Win8 desktop apps...

Can we mark this as something we want to get resolved for 1.10?

comment:36 in reply to:  35 Changed 6 years ago by bill

Replying to dylan:

What's the status of this? I'm receiving more regular requests about getting Dojo working inside native Win8 desktop apps...

Last thing I remember it might be theoretically working if you do a build. The sticking point was #16451, about loading NLS resources. But there are probably more unknown issues.

Can we mark this as something we want to get resolved for 1.10?

It didn't seem like anyone was interested in helping fix this besides me, and I got tired of fighting an uphill battle. If you have other people that want to work on it you can grab the ticket and mark it for 1.10.

comment:37 Changed 6 years ago by dylan

Milestone: future1.10
Owner: changed from bill to dylan
Status: newassigned

Fair enough... I'll see what I can do.

comment:39 Changed 6 years ago by bill

See also #17310.

comment:40 Changed 6 years ago by cjolif

Cc: cjolif added

comment:41 Changed 6 years ago by cjolif

Keywords: metro added

comment:42 Changed 5 years ago by dylan

Milestone: 1.102.0

Given the bugs filed on MS and their lack of responsiveness, unfortunately there's no way this is going to get solved for 1.10.

comment:43 Changed 5 years ago by nonplus

This ticket really needs to be split into separate items, at a minimum dealing with:

  • localized resource path mappings
  • application activation events
  • unsafe local context execution

Some of these could be worked around in your application (or build process) - in which case it would be nice to have some documentation/examples. The unsafe local context execution might be something that's too pervasive and require changes to Dojo's sources.

comment:44 Changed 5 years ago by Sebastien Pereira

Cc: Sebastien Pereira added

comment:45 Changed 5 years ago by cjolif

Another linked issue is that it seems Windows Store application require UTF8 files to have a BOM (sounds strange but is apparently the case), which we don't necessarily have and which we strip out at build time. See: https://bugs.dojotoolkit.org/ticket/17271#comment:9

comment:46 Changed 4 years ago by dylan

Milestone: 2.01.11
Resolution: fixed
Status: assignedclosed

This meta ticket has outlived its usefulness. Please open smaller tickets for things that should be addressed (ideally with pull requests!)

Note: See TracTickets for help on using tickets.