Re-wrap a modified JS function

The question came up recently about the possibility of modifying an existing javascript without duplicating it. Yesterday, I found out that it’s indeed possible. The key to the solutions is to re-wrap an existing function with it’s modifications in an ‘anonymous function.’
Here’s the scenario:
I have a page where I check for some required browser plugins before sending users on to our eLearning site; Adobe Flash, Reader and Java.

I also check for optimal OS / browser combinations.

So in this scenario I was leveraging available JS & jQuery functions as much as possible but in one particular case I need to accurately display the users browser but jQuery.brower treats all webkit browsers as Safari.

So instead of installing a new jQuery plug in or write a script to parse the user’s browser info I took advantage of a function in the Java detection script I pulled in.

Specifically the getBrowser function of the deployJava.js script (in readable format here: http://www.java.com/js/deployJava.txt).

That script isn’t helpful by itself as it returns even less info about the browser. Lumping all browsers into 2 categories: MSIE and Netscape Family. But it could return the actual user agent with a small adjustment. Here’s the un-minified function:

getBrowser: function() {
  if (this.browserName == null) {
      var browser = navigator.userAgent.toLowerCase();

      log('[getBrowser()] navigator.userAgent.toLowerCase() -> ' + browser);

      // order is important here.  Safari userAgent contains mozilla,
      // and Chrome userAgent contains both mozilla and safari.
      if ((browser.indexOf('msie') != -1) && (browser.indexOf('opera') == -1)) {
          this.browserName = 'MSIE';
          this.browserName2 = 'MSIE';
      } else if (browser.indexOf('iphone') != -1) {
          // this included both iPhone and iPad
          this.browserName = 'Netscape Family';
          this.browserName2 = 'iPhone';
      } else if ((browser.indexOf('firefox') != -1) && (browser.indexOf('opera') == -1)) {
          this.browserName = 'Netscape Family';
          this.browserName2 = 'Firefox';
      } else if (browser.indexOf('chrome') != -1) {
          this.browserName = 'Netscape Family';
          this.browserName2 = 'Chrome';
      } else if (browser.indexOf('safari') != -1) {
          this.browserName = 'Netscape Family';
          this.browserName2 = 'Safari';
      } else if ((browser.indexOf('mozilla') != -1) && (browser.indexOf('opera') == -1)) {
          this.browserName = 'Netscape Family';
          this.browserName2 = 'Other';
      } else if (browser.indexOf('opera') != -1) {
          this.browserName = 'Netscape Family';
          this.browserName2 = 'Opera';
      } else {
          this.browserName = '?';
          this.browserName2 = 'unknown';
      }

      log('[getBrowser()] Detected browser name:'+ this.browserName +
                 ', ' + this.browserName2);
  }
  return this.browserName;
}

‘this.browserName2’ is what I want but the script returns: ‘this.browserName’; So I thought it over and decided I could just replace that return statement and I’d be in business.

Here’s the code.

<script type="text/javascript" src="http://www.java.com/js/deployJava.js"></script>
<script type="text/javascript">
//Find browser (for non Safari)
if( ! jQuery.browser.safari ){
  /* *********************************
   * Modify deployJava.getBrowser()
   ********************************* */
  /**
   * Usage: browserDetect(); //execute the script
   */
  browserDetectScript=""; //set defaults
  //capture remote script contents, minus the surrounding function() and brackets {}
  browserDetectScript = deployJava.getBrowser.toString().replace('function (){','').replace(/}$/,'');
  //console.log(browserDetectScript); //view the original script contents
  //check the function contents for any key piece
  if(browserDetectScript.indexOf("return this.browserName")){
    //edit the function
    //return a different var
    browserDetectScript = browserDetectScript.replace('return this.browserName','return this.browserName2');
    //remove the log comments
    browserDetectScript = browserDetectScript.replace('g("[getBrowser()] navigator.userAgent.toLowerCase() -> "+n);','');
    browserDetectScript = browserDetectScript.replace('g("[getBrowser()] Detected browser name:"+this.browserName+", "+this.browserName2)','');
  }
  //create the new function
  var browserDetect = new Function(browserDetectScript);
  //console.log(browserDetect.toString()); //view the modified script contents
  /* *************************************
   * END Modify deployJava.getBrowser()
   ************************************* */
} else {
  function browserDetect(){
    return "Safari";
  }
}//end if not safari

//Browser compatibility
currentBrowser = browserDetect();
if( !currentBrowser.length > 0 ) {
  currentBrowser = yourBrowser();
}
console.log(yourOS() + ' + ' + currentBrowser);
</script>

In short I extract the text of the function I want with the toString() function:

deployJava.getBrowser.toString()

.

Then I remove the function wrapper: “function() {}” Next I update the return statement to get the var I want.

I also remove their log statements, just because…

Last I re-wrap the function and make it my own, like so:

var browserDetect = new Function(browserDetectScript);

So now I can call it like browserDetect(); and leverage the thorough and diligent efforts of some coders at Java.

Here’s the console output; Note the return statement at the end of each code block here:

if(this.browserName==null){var n=navigator.userAgent.toLowerCase();g("[getBrowser()] navigator.userAgent.toLowerCase() ->
"+n);if((n.indexOf("msie")!=-1)&&(n.indexOf("opera")==-1)){this.browserName="MSIE";this.browserName2="MSIE"}else{if(n.indexOf("iphone")!=-1){this.browserName="Netscape
Family";this.browserName2="iPhone"}else{if((n.indexOf("firefox")!=-1)&&(n.indexOf("opera")==-1)){this.browserName="Netscape
Family";this.browserName2="Firefox"}else{if(n.indexOf("chrome")!=-1){this.browserName="Netscape
Family";this.browserName2="Chrome"}else{if(n.indexOf("safari")!=-1){this.browserName="Netscape
Family";this.browserName2="Safari"}else{if((n.indexOf("mozilla")!=-1)&&(n.indexOf("opera")==-1)){this.browserName="Netscape
Family";this.browserName2="Other"}else{if(n.indexOf("opera")!=-1){this.browserName="Netscape
Family";this.browserName2="Opera"}else{this.browserName="?";this.browserName2="unknown"}}}}}}}g("[getBrowser()] Detected browser
name:"+this.browserName+", "+this.browserName2)}return this.browserName

function anonymous() {
  if(this.browserName==null){var
  n=navigator.userAgent.toLowerCase();if((n.indexOf("msie")!=-1)&&(n.indexOf("opera")==-1)){this.browserName="MSIE";this.browserName2="MSIE"
	}else{if(n.indexOf("iphone")!=-1){this.browserName="Netscape
	Family";this.browserName2="iPhone"}else{if((n.indexOf("firefox")!=-1)&&(n.indexOf("opera")==-1)){this.browserName="Netscape
	Family";this.browserName2="Firefox"}else{if(n.indexOf("chrome")!=-1){this.browserName="Netscape
	Family";this.browserName2="Chrome"}else{if(n.indexOf("safari")!=-1){this.browserName="Netscape
	Family";this.browserName2="Safari"}else{if((n.indexOf("mozilla")!=-1)&&(n.indexOf("opera")==-1)){this.browserName="Netscape
	Family";this.browserName2="Other"}else{if(n.indexOf("opera")!=-1){this.browserName="Netscape
	Family";this.browserName2="Opera"}else{this.browserName="?";this.browserName2="unknown"}}}}}}}}return this.browserName2
}

Macintosh + Firefox

Here’s screenshot of the code in action:
Screen shot of the browser requirements table

One caveat: Safari doesn’t like this method… Ugh.

While there are some ways to but in this case that’s fine as I already know if the userAgent is Safari thanks to jQuery.browser.

It works great and now I know it can be done!

Comments
  • jankiiahir says:

    I was in a similar situation a few weeks ago. I knew it was going to be ugly so I created a new branch and then went ahead with the merge knowing it would break.

Leave a Comment