Wednesday, February 13th, 2008

Crazy way to change third party scripts

Category: JavaScript, Tip

Paul Irish posted a crazy method for tweaking third party scripts. His problem was that he was using MultiMap (online Mapping API) and wanted to internationalize the information, but it was hard coded in the JavaScript.

To get around the problem he does this:

javascript

  1. // WARNING!!  This is such a massive hack. Oh-so-hackalicious
  2.  
  3. // Problem:     Multimap doesnt allow internationalization of its buttons, etc.
  4. // Solution:    Redefine their JS functions to use variables that are internationalized.
  5. // Assumption:  That these internal function names stay the same.
  6. // Risk:        If function names change, this code will (probably) silently fail.
  7.  
  8. // The following statements change the right-click context menu items and the map/aerial/hybrid buttons.
  9. // Instead of hard-coded strings, it will use a variable which we control.
  10.  
  11. // ON TO THE HACKS!!
  12. // Hack 1: modify the mmjr() and mmfl() functions with funcName.toString().replace()
  13. // Hack 2: use eval() to set the definition
  14. // Hack 3: browser sniff because IE and FF handle toString()'d strings differently (single-quote vs double-quote)
  15.  
  16. var isIE = $.browser.msie; // jQuery browser sniff.
  17.  
  18. eval(
  19.   "mmki.prototype.mmjr = " +  
  20.   mmki.prototype.mmjr
  21.   .toString()
  22.     .replace( isIE ? "'Move map to here'" : '"Move map to here"' ,      'i18n.retailLocator.moveMapToHere')
  23.     .replace( isIE ? "'Zoom in to here'" : '"Zoom in to here"' ,        'i18n.retailLocator.zoomInToHere')
  24.     .replace( isIE ? "'Zoom out from here'" : '"Zoom out from here"',   'i18n.retailLocator.zoomOutFromHere')
  25.   );
  26.  
  27. eval(
  28.   "MultimapViewer.prototype.mmfl = " +  
  29.   MultimapViewer.prototype.mmfl
  30.   .toString()
  31.     .replace( isIE ? "'Map'" : '"Map"',       'i18n.retailLocator.map')
  32.     .replace( isIE ? "'Hybrid'" : '"Hybrid"', "i18n.retailLocator.hybrid")
  33.     .replace( isIE ? "'Aerial'" : '"Aerial"', 'i18n.retailLocator.aerial')
  34. );

Yowser :)

Posted by Dion Almaer at 6:22 am
5 Comments

+++--
3.4 rating from 18 votes

5 Comments »

Comments feed TrackBack URI

now, this really looks like an ugly and very bad hack – without knowledge of the libs internal: can’t believe, that there’s no other way around …

Comment by aurora — February 13, 2008

Now, that’s what I call inheritance! :-) Crazy but cute.

Comment by yunosh — February 13, 2008

1. This method also breaks if the localization string changes
2. Browser detection isn’t necessary. Use RegEx in replace() method. E.g.:
…replace(/[‘”]Move map to here[‘”]/, ‘i18n.retailLocator.moveMapToHere’)
3. Cute hack, but there’s no mention of how this script is actually injected into the page. GreaseMonkey, I presume?

Comment by broofa — February 13, 2008

@broofa:

I suspect he’s just loading this *hack* script after the core library. This code is simply taking the original method, converting it to a string, replacing some string tokens and converting it back to a method.

I’ve used a similiar technique before–it’s ugly, but it does work (and has worked as earlier as IE4/NS4.)

Comment by Dan G. Switzer, II — February 13, 2008

@broofa:
1. Yes, it will break in that case too. It has a lot of potential to break. It should probably have some added measures built in so that it wont throw an error to the end-user. How about I add a try/catch hack? (just kidding :)
2. Smart move with the regex. That cleans it up a bit. Thanks.
3. Yup Dan’s right — just running that script sequentially in a separate js after the library is included.

@aurora:
I agree its terrible and ugly, but I couldn’t think of a cleaner way around it. Imagine if the Google Maps API forced you use a single kind of icon, and the image file’s path was hardcoded into a createIcon() function. Do they leave you any other options?

Comment by PaulIrish — February 17, 2008

Leave a comment

You must be logged in to post a comment.