-1

I have a script that iterates through values passed in an array and checks whether those items are natively supported by a browser. This works fine in Chrome, Edge, FireFox and Safari, but IE11 and older (the browsers that really need this to work) throws an error. The array values are strings (as can be seen below) but for some reason, IE11 is treating them as objects, which means when I try to check for a . in the string, IE is erroring out.

I have tried converting the array item toString, but that just results in object object or object undefined.

I have setup a CodePen which contains the full set of code: https://codepen.io/willstocks_tech/pen/YBEzLW?editors=1012

The version that can be used in IE is: https://s.codepen.io/willstocks_tech/debug/YBEzLW/mWAoNxdogGvr (although this might expire!)

//https://github.com/willstocks-tech/dynamically-polyfill-features-for-a-script/releases/
dynamicPolyfill(
 ['IntersectionObserver', 'IntersectionObserverEntry', 'Object.assign', 'Array.copyWithin']
 ,'https://cdn.jsdelivr.net/npm/quicklink@1.0.0/dist/quicklink.umd.js' 
 ,'quicklink()' 
)

function dynamicPolyfill(tocheck, scriptToPolyfill, functionToRunonLoad) {
 if(typeof Promise !== "undefined"){
  var checkPromises = [];
  if(Array.isArray(tocheck)) {
   tocheck.forEach(
    function(tocheck){
     checkPromises.push(checking(tocheck))
    }
   )
  } else {
   checkPromises.push(checking(tocheck))
  }
  checkPromises = checkPromises.filter(function(p){return p !== undefined}).join(' ');
  loadPolyfill(checkPromises, scriptToPolyfill, functionToRunonLoad)
 } else {
  promiFill(tocheck, scriptToPolyfill, functionToRunonLoad);
 }
}

function promiFill(tocheck, scriptToPolyfill, functionToRunonLoad){
  var promPolyfill = document.createElement('script'); 
  promPolyfill.src = ('https://polyfill.io/v3/polyfill.min.js?features=Promise'); 
  document.body.appendChild(promPolyfill); 
  promPolyfill.onerror = function(response) { 
   console.error("Polyfilling promise failed", response); 
  } 
  promPolyfill.onload = function(tocheck, scriptToPolyfill, functionToRunonLoad) {
   dynamicPolyfill(tocheck, scriptToPolyfill, functionToRunonLoad);
  }
}

function checking(check){
 var splitChars = '.';
 if ((check in window) != true || (check in this) != true) {
  if (check.indexOf(splitChars) >= 1) {
   var split = check.split('.');
   var firstWord = window[split[0]];
   var lastWord = new Object(split[split.length - 1]);
   if (lastWord in firstWord != true && lastWord in firstWord.prototype != true) {
    return check;
   }
  } else {
   return check;
  }
 }
}

function loadPolyfill(url, scriptToPolyfill, functionToRunonLoad) {
 if(url !== "") {
  var polyfill = document.createElement('script'); 
  polyfill.src = ('https://polyfill.io/v3/polyfill.min.js?features='+encodeURIComponent(url)); 
  document.body.appendChild(polyfill); 
  polyfill.onerror = function(response) { 
   console.error("Loading the polyfill(s) failed!", response); 
  } 
  polyfill.onload = function() {
   loadMyScript(scriptToPolyfill, functionToRunonLoad)
  }
 } else {
     loadMyScript(scriptToPolyfill, functionToRunonLoad)
 }
}

function loadMyScript(url, functionToRunonLoad) {
 if(Array.isArray(url)) {
  var promises = [];
  url.forEach(
   function(url){
    promises.push(nonblankURL(url));
   }
  );
  Promise.all(promises)
   .then( 
    function() {
     initialiseMyScript(functionToRunonLoad)
    }
  ).catch(function(error){return error})
 } else if (!Array.isArray(url) && url !== null && url !== '') {
  nonblankURL(url)
   .then( 
    function() {
     initialiseMyScript(functionToRunonLoad)
    }
  ).catch(function(error){return error}) 
 } else {
  initialiseMyScript(functionToRunonLoad) 
 }
}

function nonblankURL(uri){
 return new Promise( 
  function(resolve, reject) { 
   var thescript = document.createElement('script');
   thescript.src = encodeURI(uri);
   document.body.appendChild(thescript);
   thescript.onerror = function(response) {
    return reject("Loading the script failed!", response);
   } 
   thescript.onload = function() {
    return resolve(uri);
   } 
  }
 )

}

function initialiseMyScript(functionToRunonLoad) {
 if(Array.isArray(functionToRunonLoad)) {
  functionToRunonLoad.forEach(
   function(functionToRunonLoad){
    initScript(functionToRunonLoad)
   }
  )
 } else { 
  initScript(functionToRunonLoad)
 }
 function initScript(fn) {
  try {
   window[fn];
  } catch(err) {
   console.error('There was an error: ', err, err.name, err.stack);
  }
 }
}

All other browsers seem to handle this fine, but IE11 and older throw the following error: SCRIPT438: Object doesn't support property or method 'indexOf'

I can't work out for the life of me how to get this to work in IE, but also in all other browsers at the same time!

  • How does it come, that you're trying to use `indexOf` of `null`? I mean, when the condition passes, `check` doesn't exist ... – Teemu Feb 19 '19 at 11:58
  • The code in your question had a syntax error (I discovered this when putting it in an on-site runnable snippet). I've added what seems to be the appropriate `}`, but please check it against your actual code. It's **always** best to use copy and paste to copy your code (after first getting it down to the absolute minimum [MCVE](/help/mcve)), to avoid introducing errors like that. – T.J. Crowder Feb 19 '19 at 12:01
  • 1
    Apologies for the poor code snippet - I have now added the full code snippet - the error is not at Promise, but is at `if (check.indexOf(splitChars) >= 1) {` – willstocks_ Feb 19 '19 at 12:12

1 Answers1

0

You can see in the IE11 debugger that tocheck is an Event object at that point (which obviously doesn't have indexOf). That's because of this code:

promPolyfill.onload = function(tocheck, scriptToPolyfill, functionToRunonLoad) {
    dynamicPolyfill(tocheck, scriptToPolyfill, functionToRunonLoad);
}

The first and only argument a DOM event handler receives is an event object, but you're accepting it as tocheck and then calling dynamicPolyfill with that event.

You may have meant:

promPolyfill.onload = function() {
    dynamicPolyfill(tocheck, scriptToPolyfill, functionToRunonLoad);
};

or similar. In any case, the issue is calling indexOf on an Event object.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Ahaaaa - @t-j-crowder thank you! Sorry, I’m still fairly new to JS and was pulling my hair out as I couldn’t work out why it kept thinking it was an object! – willstocks_ Feb 19 '19 at 12:20