Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How did I lose JavaScript built-in objects and all global variables?

I'm working on an Umbraco site that needs to work in the big browsers, including IE 11, and I've run into a weird issue that I can only replicate on IE 11.

At some point, the script for a TinyMCE plug-in tries to execute this code (about four calls deep) in response to a blur event:

  function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }

and it throws a "Object doesn't support this action" exception when trying to create the RegExp object. cls is defined and has the value I expect.

While paused (using Visual Studio debugger) on the unhandled exception, I did a little checking.

It turns out that RegExp was undefined. I found this extremely weird.

A little more investigation revealed that ALL the built-in objects were undefined. Number, Array, Object, Math... all of them. Also, while I could enumerate the global keys, all the values were also undefined.

Weirder, I could use the console or immediate-execution windows, within the problematic scope, to create regular expression objects by using the /pattern/ syntax.

But this condition is true only in the scope of the event handler. As soon as the event handler exits, all the built-in objects and global variable values were restored.

How is it even possible to lose access to the built-in JavaScript objects, without losing access to the basic JavaScript parser and engine?

And, once lost, is it possible to restore them?

like image 471
Alan McBee Avatar asked Nov 10 '16 22:11

Alan McBee


1 Answers

I experienced this problem as well, and assuming you're also having trouble with the TinyMCE CodeMirror plugin, the problem is triggered by this line in codemirror.js:

on(window, "blur", function () { return forEachCodeMirror(onBlur); })

where window refers to the iframe containing the CodeMirror editor.

This iframe is inside of a TinyMCE dialog. I've discovered the error only occurs when the iframe (or an element inside it) loses focus at the same time that the dialog is closed, removing the iframe from the DOM. You can test this by first clicking outside the iframe (on the page overlay, for example) before closing the dialog.

IE11 seems to be calling the blur event after it has started destructing the iframe's window object. I would classify this as a bug in IE11, which will never get fixed. Since we probably don't care about the blur event in an iframe that's being removed from the DOM, we can work around the problem by modifying the problem line to skip it in that case:

on(window, "blur", function () { if (window.RegExp) return forEachCodeMirror(onBlur); })
like image 195
Steven Barnett Avatar answered Oct 17 '22 13:10

Steven Barnett