2

I maintain some donation forms that include the GeoTrust SSL 'smart icon'. This is generated by including a script reference as so within the document where you want the seal to appear:

<script type="text/javascript" src="//smarticon.geotrust.com/si.js"></script>

Their script is obviously doing a document.write(), and if/when geotrust is being slow it blocks rendering of my donation form for up to a few seconds.

I can't use the 'async' attribute, because of the document.write(). I can't edit or rewrite GeoTrust's javascript of course. And loading the js in the footer or doing the 'append to the head' approach doesn't help either because the script needs to execute within the markup where we want the icon to appear. A further complication is that these donate pages are also part of a different third-party system full of their own javascript etc.

Here's an approach that seems to work, but I'm wondering if there's a better way:

<div id="vs_seal"></div>
<script type="text/javascript">
r(function() {
  var div = document.getElementById('vs_seal');
  writebackup = document.write;
  document.write = function(markup) {
    div.innerHTML = markup;
    document.write = writebackup;
  }
  var script= document.createElement('script');
  script.type= 'text/javascript';
  script.src= '//smarticon.geotrust.com/si.js';
  document.body.appendChild(script);  
});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
</script>

(PS I totally stole that domready test from http://www.dustindiaz.com/smallest-domready-ever )

EDIT: If it isn't clear, what I'm doing is

  • writing a div
  • waiting for the dom to be ready (last line)
  • saving document.write as a variable
  • overriding document.write to instead insert the output into a div
  • loading the script dynamically via appendChild
  • when the script calls the overriden document.write, the last line of the override is to reset document.write to the original version (that I saved as a variable).

EDIT: After the comments below, I've simply put it into an IFRAME instead.

<style>#vs_seal iframe{border:0 none;}</style>
<div id="vs_seal"></div>
<script type="text/javascript">
r(function() {
  var div = document.getElementById('vs_seal');
  var iframe = document.createElement('iframe');
  iframe.width = 118;
  iframe.height = 55;
  iframe.frameborder = 0;
  iframe.scrolling = "no";
  iframe.seamless = "true";
  iframe.src = 'about:blank';
  var content = '<!DOCTYPE html>'
  + '<head><title>Dynamic iframe</title>'
  + '<style>body{margin:0;padding:0;border:0;}</style></head>'
  + '<body><script type="text/javascript" src="//smarticon.geotrust.com/si.js">'
  + '<\/script><\/body><\/html>';
  div.appendChild(iframe);
  iframe.contentWindow.document.open('text/html', 'replace');
  iframe.contentWindow.document.write(content);
  iframe.contentWindow.document.close();

});
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
</script>

I originally tried pulling in the content into a hidden IFRAME and then copying the innerHTML from the IFRAME into my div, but GeoTrust's javascript that makes their popup window all pretty needs to be executed in the context its being clicked on. The innerHTML doesn't execute the javascript, and there seemed to be no advantage to not just displaying the IFRAME.

Thanks for the comments and suggestions!

Will
  • 812
  • 1
  • 6
  • 13
  • 1
    if it's the only script that needs document.write(), it should be fine until something better comes along. – dandavis May 21 '15 at 21:01
  • 2
    _"I can't edit or rewrite GeoTrust's javascript of course"_ sure you can, download the js file, rewrite it to use something other than document.write, and upload the new js file to your server and link to that js file instead of the one on GeoTrust's server. – Patrick Evans May 21 '15 at 21:07
  • Patrick, since the point of GeoTrust's script is to provide SSL verification, rewriting and hosting locally isn't going to be an option. – Will May 21 '15 at 21:11
  • 1
    If a script uses `document.write`, you cannot load it asynchronously. Point. If you need to speed up the rest of your page, include the script in an iframe. – Bergi May 21 '15 at 21:12
  • dandavis -- I'm pretty sure that I'm only temporarily overriding document.write() -- the last line in my overrride function is to reset document.write back to the value I'd stored it in. Am I missing something? – Will May 21 '15 at 21:13
  • 1
    `document.write()` is overriden for an indeterminate amount of time and other scripts can run in that time. Because you are loading your script async, other scripts may run before your script is loaded. If any of those scripts try to use `document.write()`, your hack will break things. Also, your hack is also making an assumption that the GeoTrust script uses exactly one call to `document.write()`, not zero, not more than one. – jfriend00 May 21 '15 at 21:22
  • Good point jfriend00, particularly on the async issue. I've looked at the GeoTrust script and it does only use one call. What I guess I need is to find callbacks for when that GeoTrust script is first loaded and when it has completed. – Will May 21 '15 at 21:28
  • Possible duplicate of [including javascript in another included javascript](http://stackoverflow.com/questions/38518531/including-javascript-in-another-included-javascript) – Paul Sweatte Sep 26 '16 at 17:20

0 Answers0