I have been determining the version of the IE Trident engine using javascript conditional compilation:
var ieVersion = undefined;
/*#cc_on
ieVersion = Math.floor(#_jscript_version);
#*/
This worked fine for IE8, 9 and 10. In IE11, the conditionally-commented block does not execute, unless I use the F12 dev tools to emulate IE10 (in which case it returns the correct value, 11).
This is confusing, since the MSDN page on conditional compilation specifies that it applies to Internet Explorer 11. (UPDATE 2015-02-03: this page has since been updated to explicitly state that its content does not apply to IE11 in standards mode.) I've not found any information online to suggest that IE11 should not support conditional comments.
Does anyone have any information about this? Can anyone reproduce this behaviour in IE11?
Edit: the relevance of this is in IE's <audio> support. I have a web app that requires playback of around 50 short (~1sec) audio files, which should be played in a (pseudo-)random order, and individually after user interaction. The problems are various:
IE9 has an undocumented limit of 41 audio elements (whether declared in HTML or as JS objects). All subsequent audio files silently fail to load and play. (Each of the 41 elements can have its source re-assigned, but every second re-assignment also fails silently. I would love to see the code behind these bugs...)
IE10 and IE11 "stutter" when playing short sounds: they play a fraction of a second, then pause, then continue on. The effect to the end-user is that the audio is unintelligible. (The audios have preload="auto" and report a non-zero buffer.)
Naturally there's no practical way to feature-detect these issues, hence the browser-detect. I generally feel user-agent sniffing is too dicey for production code; the #cc_on technique seemed more robust.
My workaround for IE9 is to serialise the app state to sessionStorage after the 25th sound, then reload the page and deserialise.
In IE10/11, my workaround is to play the last 90% of the audio at 0 volume, which seems to force IE to actually buffer the file.
Yes, IE11 has removed javascript conditional compilation
The google search linked in the question returns this question as its third result, after two MSDN pages also linked above. This establishes the lack of a better source, so I think this question (including comments) should be considered the authoritative reference for the fact that Javascript conditional compilation is not available in IE11.
I have submitted feedback on the MSDN pages to the effect that they are incorrect.
Update 2015-02-03: MSDN now acknowledges that IE11 no longer supports #cc_on.
Some workarounds are as follows:
User-agent detection
/\([^)]*Trident[^)]*rv:([0-9.]+)/.exec(ua)
will parse IE11's UA string and return the "revision number" at the end.
ScriptEngineMajorVersion() (thanks #Teemu)
var tridentVersion =
typeof ScriptEngineMajorVersion === "function" ?
ScriptEngineMajorVersion() : undefined
should evaluate correctly on all browsers, but we can't guarantee ScriptEngineMajorVersion will not be dropped without warning just as conditional compilation has been.
Thanks to all commenters.
Related
A teammate of mine wrote some code about a short time ago which navigated about the DOM elements in out HTML page to pre-fill some fields in a modal based on the already existing data in an object (the modal allowed a user to edit that data). The items are generated generically from a database table.
function showModal(editImage) {
var modal = document.getElementById('myModal');
var span = document.getElementsByClassName("close")[0];
var nameAndTitle = editImage.srcElement.parentElement.innerHTML;
var parent = editImage.srcElement.parentElement.parentElement;
etc....
The problem is, they only tested that it worked in Chrome. The code never worked in firefox, it seems. When I try to open one of the modals in firefox, I get the console output "TypeError: editImage.srcElement is undefined"
My question is, is there a more "correct" way to access this data that will work for any browser, or do I need to check what browser I am in and access that information in a different way depending on the browser being used?
Your immediate answer is: change srcElement to target. The Mozilla Developer Network is a very good (one of many) resource to check for standards compliance. A visit to their site for srcElement indicates that it is non-standard and makes the suggestion on the correct way (target).
Unfortunately, even APIs that are standard don't always work in all browsers. Usually, parts of a standard are implemented piecemail. Checking with authoritative sources is vital to know what is supported where.
Other resources:
The World Wide Web Consortium (W3C) for HTML, CSS, XML and many others
The European Computer Manufacturer's Association (ECMA) for JavaScript
CanIUse.com Good for quick compatibility compliance checking
As for your explicit question:
"My question is, is there a more "correct" way to access this data that will work for any browser, or do I need to check what browser I am in and access that information in a different way depending on the browser being used?"
Use standards and check for support (via the resources I've provided above) to have the best chance at cross-browser code.
DO NOT write code that checks the browser type and version to see if your code will run (browser detection) because:
There are too many browsers and too many versions - this sucks!
Browsers can and will lie to you about what they are!
Use "feature detection" when in doubt. Feature detection is code that evaluates whether a feature exists and uses it if it does. If it doesn't a fallback is provided. Here's a very common one for IE8 (and lower) browsers that did not yet support the W3C standard for event handling:
// Here we are attempting to obtain the value of the
// addEventListener property of the window object.
// IE 8 doesn't implement this property so "undefined"
// will be returned. But, because we are attempting to
// use the value as the condition of an if/then construct
// "undefined" will be converted to a boolean. "undefined"
// is a "falsey" value, so it will convert to false.
// This means that if the else portion of our construct
// is reached, we have a browser that doesn't support
// addEventListener
if(window.addEventListener){
// W3C standards are supported - do things the standard way
obj.addEventListener("click", someFunction, capture);
} else {
// Must be IE 8 or less - do things the IE way
obj.attachEvent("onclick", someFunction);
}
This is but one way to use feature detection, but it typically hinges on converting a value to a boolean. See more on it here.
That function showModal is probably an event listener, so the argument editImage is actually an Event object.
As such, the actual property that reports the source of the event - and the only one supported by Firefox - is target, while srcElement is a legacy property that was created by Microsoft and Webkit/Blink based browsers kept supporting it for compatibility. But not Firefox.
In short: use target or, if you need to support older version of Internet Explorer, try with (editImage.target || editImage.srcElement).
srcElement is from IE. The standard property is target.
You should do this:
var target = editImage.srcElement || editImage.target;
I was just forced into a browser upgrade (IE8 to IE11) while in the middle of testing. I've lost some essential functionality with some javascript that suddenly doesn't work in my .NET site.
This section of the code was written when I was in grade school, so I'm not extremely familiar with it, but what seems to be the problem is a call to form.all. I have to assume that call was built into javascript at some point - there's no definition for it in the code.
There are 7 "if statements" that use form.all and they are all written the same way:
if(form.all(cTag + "PersonNum") != null)
form.all(cTag + "PersonNum").value = personNumber;
The error:
JavaScript runtime error: Object doesn't support property or method 'all'
In newer versions of JavaScript, is there a version of form.all that performs the same action? All I really need is for someone to point me in the right direction.
A weird note: the same JavaScript code IS working in production on IE11
EDIT Ok, I found a line that was minimized. It looks like form is a created variable.
var form = document.forms(0);
EDIT2 Compatibility view/mode was the solution after all. I had added our production site's domain to the compatibility list and didn't think about it; adding 'localhost' fixed the issue. You just have to set it to the right domain first for it to work :)
Check the browser compatability mode when your running in production it's probally on IE8.
You can use obj.getElementsByTagName("*")
You could also add an All method to the prototype if it's not there.
IE introduced an all property for certain DOM objects (e.g. document) but it was never part of any W3C standard. It allowed access to DOM objects by name or ID using:
var element = document(elementNameOrID);
or
var element = document[elementNameOrID];
that is, it is a property that could use the same syntax as a method. Neat. Some other browsers supported it for compatibility, but it pretty much went out of use with IE 6 (not sure when IE started supporting getElementById, I think it was IE 5). But IE continued to think name and ID attributes were the same thing until IE 8 in standards mode.
Support for all has been dropped from IE 11 in standards mode.
If form is a reference to a form element, and cTag + "PersonNum" is the name of a form control, then the simplest fix is to change:
form.all(cTag + "PersonNum").value
to
form[cTag + "PersonNum"].value
which takes advantage of named form controls being made properties of the form that contains them. This behaviour is standardised and supported by browsers from the very beginning (i.e. every where) and is future proof (it's not going to change).
Why does this expression:
typeof document['domConfig']
throw an error in Firefox (4)?
All the other browsers (IE9, Chrome 10, Safari 5, Opera 11) do not throw an error on that line!
Live demo: http://jsfiddle.net/TvBeT/
Btw, document.domConfig is a property defined in the DOM Core spec.
None of the other browser define document.domConfig, so they return undefined.
More interesting, firefox 4 is the only browser that can run document.normalizeDocument(),
which method gives domConfig a value while it is running, merging adjacent text-nodes and adjusting the containment of bad html tags on an existing or newly created Document..
From the MDN page on domConfig:
This feature has been removed from the Web. Though some browsers may still support it, it is in the process of being dropped. Do not use it in old or new projects. Pages or Web apps using it may break at any time.
I have some code in my application that wraps function.apply and function.call in try/catch blocks. It's handy for catching errors and building up a pseudo-stack using arguments.caller but it plays havoc with IE's debugger.
I can turn off the wrapping with a url parameter but I'd like to turn it off automatically if the debugger is attached. I can't find a way to detect the debugger. Any ideas?
Not sure for IE8, but you can detect if the debugger is running in IE9/IE10/IE11 by checking:
var isIeDebugging = !!window.__IE_DEVTOOLBAR_CONSOLE_COMMAND_LINE || ('__BROWSERTOOLS_DOMEXPLORER_ADDED' in window);
e.g. see http://jsbin.com/IJOwuje/5
However, in IE9/IE10 this is set to true for a window that has run the debugger just once, even if the debugger now closed.
Also in IE11 the various window.__BROWSERTOOLS* keys seem to only appear depending upon which debugger tab is open or used, so not 100% reliable for checking if the debugging frame is open...
This isn't the answer you wanted, but I've handled this in the past by having a small bit of loader JS that begins by checking the hash, if any, in the URL, for a secret code, like:
mysite.com/#mXVa
So the loader checks and if location.hash == 'mXVa', my loader loads the debug versions of all the scripts on the page (no try/catch, etc) rather than the minified, error-eating variety.
Is there an easy way to find parse errors in javascript code?
Last week I was debugging a javascript problem where the first javascript function that was called gave an 'object expected' error. I later determined that this was because the browser wasn't able to parse my javascript code. I eventually solved the problem but it was a painful process that involved pouring over my code line by line, trying to find my mistake.
There must be an easier way.
Use a tool like Jslint or an alternative browser.
Until recently, IE was the only browser that did not have built in development assistance. Other browsers will a) not come to a grinding halt on the first error they encounter, and b) tell you what and where the problem in your code is.
My favorite "quick ad easy" way to test IE syntax problems is to load the page up in Opera. It parses code like IE but will give you meaningful error messages.
I'll clarify with an example:
var foo = {
prop1 : 'value',
prop2 : 'value',
prop2 : 'value', // <-- the problem
};
If I remember correctly: In IE6 and IE7 the code will break because IE demands leaving the last comma out. The parser throws a fit and the browser simply stops. It may alert some errors but the line numbers (or even filenames) will not be reliable. Firefox and Safari, however, simply ignore the comma. Opera runs the code, but will print an error on the console indicating line number (and more).
Easiest way to write JavaScript is with Firefox + Firebug. Test with IE and have Opera tell you what is breaking when it does.
What browser are you using? IE8 has great build-in feature to debug javascript, for Firefox, Firebug is great.
Checking that the values passed into functions are correct and throwing your own errors if they aren't will help you track down problems faster.
Safari 4 (which runs on both Mac OS X and Windows) comes with some development tools (including a debugger) that are very useful. If you prefer using Firefox, Firebug provides similar functionality.
JSLint can help you track down simple errors.
Steve