Ignoring "syntax errors" in IE11 - javascript

I have an (ASP.Net) application that has the following client-side Javascript, to facilitate copying to clipboard:
var ua = window.navigator.userAgent;
var is_ie = /MSIE|Trident/.test(ua);
if (is_ie) {
var input = document.getElementById("inputcopy"); // select it
input.value = text;
input.select();
document.execCommand("copy");
this.focus();
}
else {
navigator.clipboard.writeText(text).then(() => {
writeLog('Copy successful');
if (showalert == true) alert('Copied to clipboard');
}).catch(() => {
writeLog('Copy failed');
if (showalert == true) alert('Copy to clipboard failed');
});
}
We need to be compatible with all "modern" browsers - Chrome, Firefox and, don't shoot the messenger, IE11. The first two are fine, but the latter ...
As IE doesn't support the navigator.clipboard I've got the if (is_ie) in there, which works fine. However, IE doesn't know about the Promise in the non-IE section, and complains horribly about "Invalid Syntax" at
navigator.clipboard.writeText(text).then(() => {
even though it'll never actually run it.
How can I tell IE to ignore that bit of code, or work around this issue? I've looked at conditionally loading a separate JS file based on browser, but that doesn't look like much fun. Is there a better option?

Adding my comment as an answer by OP's suggestion.
You can try eval() to get around this issue. What eval() does is parse a string into an executable code. This will literally make IE ignore this code since it's not gonna execute anyway.
Yes, we don't typically use eval(), but rare scenarios like this are perfect reasons to use it.
Here's some resource about eval: Why is using the JavaScript eval function a bad idea?
Or if possible, just use a promise polyfill.
As #Quentin explained, merely using the function expression should easily fix this without using eval().

You can't make a JavaScript parser skip over syntax in parts of a program it isn't going to run (to oversimplify the situation horribly: It still needs to parse that bit of the program to find the } that ends the else block.
Either write your JS to use syntax that is supported by IE (i.e. use a function expression instead of an arrow function) or transpile your JS to a version that IE will support (with a tool like Babel).

Related

Internet Explorer: Ignore unknown ES6 syntax

To fix a bug that only occurs in Firefox, I need to use the loaded Promise of a FontFace. I currently use the following code for that:
if (document.fonts) {
for (var fontFace of document.fonts.values()) {
if (fontFace['family'] == fontFamily) {
fontFace.loaded.then(doStuff);
}
}
} else {
doStuff();
}
This works and only targets the browsers that support the font loading API. But because of the for .. of, Internet Explorer logs an error and stops the JS execution. Putting the code in a try .. catch block doesn't work, ignoring the error via window.onerror would probably work, but is quite hacky.
Is there a way to iterate over document.fonts.values that is also supported by IE or do you know a better way to use the loaded Promise in browsers that support it?
I'd recommend
const fontFace = Array.from(document.fonts).find(face => face.family === fontFamily);
if (fontFace) {
fontFace.loaded.then(doStuff);
}
Array.from creates an array from an iterable, and then you can use the normal Array.prototype.some to check for matches.
You could then simplify your whole check to
const fontFace = document.fonts &&
Array.from(document.fonts).find(face => face.family === fontFamily);
if (fontFace) fontFace.loaded.then(doStuff);
else doStuff();
assuming you want to run doStuff if not of the font faces match either.
Unfortunately, you can't use for-of iteration in your code, when it is supposed to run in an unsupported browser. The thing is that error occurs at the moment of parsing code before your condition will be executed and checked.
If you really want to use for-of, you will need to create a special JS-bundle for modern browsers or process your code with Babel to convert your code to es5-compatible.
I solved the problem with the following code:
if (document.fonts) {
var iter = document.fonts.values();
do {
var item = iter.next();
var fontFace = item.value;
if (fontFace && fontFace['family'] == fontFamilyStr) {
fontFace.loaded.then(doStuff);
}
} while (!item.done);
} else {
doStuff();
}
IE doesn't log an error anymore and the code works in Firefox / Chrome.

Enable/Disable debug code dynamically

I'm writing a decent sized JavaScript animation library, that I would like to include debugging code in. I could easily do a check :
if(myLib.debugger){
console.warn('warning message');
}
However if this runs a couple thousand times a second, it would eventually cause performance issues. Add in a few more checks throughout the code and the effect will be even more noticeable.
What I'm wondering is if it would be possible to check onload if the debugger should be enabled, and if so... turn something like this:
//debugger if(!this.name) console.warn('No name provided');
into:
if(!this.name) console.warn('No name provided');
Leaving the code commented if its not enabled, and uncommenting it if it is, thus removing any possible performance issues. Could this be done somehow with a regular expression on the entire script if loaded in through ajax? I'm trying to avoid the need for 2 versions of the same code, lib.dbug.js and a lib.js.
Cross browser compatibility is not of great importance for this (I'm really only worried about new browsers), I see it as nice to have item. If its possible however, it would be a great thing to have.
Any insight would be greatly appreciated.
The simplest way to do this would be to check if the debugger should be disabled and if so, replace it with a mock object that does nothing at the very start of your script:
if (!myLib.debugger) {
window.console = (function () {
var newConsole = {};
var key;
for (key in window.console) {
if (typeof window.console[key] === 'function') {
newConsole[key] = function () {};
}
}
return newConsole;
}());
}
The overhead of this approach should be negligible.
If this is a JavaScript library... then I'd expect as a 3rd party developer that I could download/use 2 versions. The production version (no debug, AND minimized). If I wanted to debug, I would point to the debug version of the library instead.
e.g.
<script src="foo-lib-min.js"></script>
<!-- swap to this for debugging <script src="foo-lib-full.js"></script>-->

programmatic way to check which version is installed?

Is there a way through javascript to see what version (or rollup) the crm organization/server is on? What I really want to know is if I am on UR11 or before.
I've tried:
Xrm.Page.context - but nothing about versions (did I miss something?)
Checking if (crmForm == null) (Since that was disabled as of UR12) The problem is that if the org enables HTC support then crmForm will not be null, and I need to know what version with or without HTC support enabled.
What I've done for now is put the onus on the solution installer to modify a javascript file that has the "isRollup12" variable to true or false, which is quite clunky.
There is a global JS variable you could check:
alert(APPLICATION_FULL_VERSION);
//on UR12 '5.0.9690.3236'
//on UR11 '5.0.9690.2839'
//and so on...
But this method isn't supported, so use at your own risk.
you can check if the getClientUrl function is defined, it's a new function included inside UR12.
var isRollup12 = false;
if (Xrm.Page.context.getClientUrl !== undefined) {
isRollup12 = true;
}

Stop jQuery function from executing in IE

I'm having some code that sadly doesn't work in Internet Explorer and because it's not absolutely neccesary to have this code work in all browsers I'd like to stop it from executing in IE unless there is someway to fix it so it works in IE too (see this thread). How would this be (if it is) possible? Thanks
jQuery has functionality for seeing if a browser is any form of MSIE
if (!$.browser.msie) {
// jquery function
}
You can use Conditional comment statements to do things in IE differently.
Take a look here http://msdn.microsoft.com/en-us/library/ms537512(v=vs.85).aspx
You would want to test to see if the browser is not IE and then do the code.
Or you can use some jQuery browser detection which would allow you only to execute specific javascript code depending on the browser.
if (!$.browser.msie) {
// jquery function
}
However I would recommend trying to get your javascript code to work in all browsers (maybe not IE6 ;) )
The jQuery object exposes a "browser" property:
if (jQuery.browser !== "msie") {
// do the thing
}
Use:
if ( !jQuery.browser.msie ) {
//Your code
}

Why would Dojo 1.6 fail to properly load javascript file in IE8 using dojo.require?

The following code worked with Dojo 1.5 in Firefox and Internet Explorer 8.
With Dojo 1.6, it still works in Firefox, but does not work in IE8.
I get an Object doesn't support this property or method error when wrappingFunctionInPlainJsFile() is called.
HTML page:
<div dojoType="widget.MyCustomWidget"></div>
In widget/MyCustomWidget.js
dojo.provide("widget.MyCustomWidget");
dojo.require("js.plainJsFile");
dojo.declare("widget.MyCustomWidget", [dijit._Widget, dijit._Templated], {
...
// this gets called when the widget is clicked on in the UI
run: function() {
wrappingFunctionInPlainJsFile();
},
...
});
In js/plainJsFile.js
dojo.provide("js.plainJsFile");
function someFunction() {
}
function wrappingFunctionInPlainJsFile(){
new someFunction();
}
Any ideas on what I am doing wrong would be greatly appreciated.
Note: If I import the plainJsFile.js directly on the HTML page instead of using dojo.require then I have no problems.
I believe that the purpose of the dojo.require system to break your code up into modules where those modules aren't just arbitrary chunks of js, but dojo.declare'd objects. When you write dojo.provide("js.plainJsFile"), by convention I'd expect there to be an global object called "js" which had a property "plainJsFile". See the code example on this page.
I actually use dojo.require the way that you do, ignoring the convention I'm describing, and it works just fine -- in firefox. IE won't swallow it though. IE will behave if all the required js files are compressed into a single file (which you mentioned solves your problem).
So, basically, I think that IE is less flexible about scope while dojo.require is doing its thing, and you putting function declarations in a "module" like that is breaking things. Try going with the convention and see if that helps.
I tried the dojo mailing list and got a fix courtesy of Karl Tiedt.
See here: http://dojo-toolkit.33424.n3.nabble.com/Why-would-Dojo-1-6-fail-to-properly-load-javascript-file-in-IE8-using-dojo-require-td3204800.html#a3204894
Copy/paste of solution.
"Its an IE quirk....
dojo.provide("js.plainJsFile");
(function() {
function someFunction()
wrappingFunctionInPlainJsFile = function() {
new someFunction();
}
})();
should work... I always use my name spaces though and do it this way
dojo.provide("js.plainJsFile");
(function(pjsf) {
pjsf.someFunction = function()
pjsf.wrappingFunctionInPlainJsFile = function(){
new someFunction();
}
})(js.plainJsFile);
"
Note: I tried the above solution and it worked for me in IE8 and Firefox.

Categories

Resources