Dynamic insertion of Google AdWords conversion tracking explodes in safari - javascript

I'm working on a single page app that will probably fire more than 1 conversion per pageload.
I need to fire the google conversion snippet, so I assumed that I could throw it in at run time. The snippet looks something like this:
<script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = XXXXXXXX;
var google_conversion_language = "en";
var google_conversion_format = "2";
var google_conversion_color = "ffffff";
var google_conversion_label = "XXXXXXXXXXXXXXX";
var google_conversion_value = 25.00;
/* ]]> */
</script>
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion.js">
</script>
I have been using javascript to insert the snippet when a conversion has fired. I'm doing it like this:
function(id,url,content){
// add script
var script = document.createElement("script");
script.type = "text/javascript";
if(url) script.src = url;
if(content) script.text = content;
var bucket = document.getElementById(id);
bucket.appendChild(script);
debugger;
}
This works in all the browsers I've tried it in, except safari.
In safari, when the 2nd script tag is added, the entire body tag's content is replaced with a google iFrame. The whole dom is nuked in fact. The head's content is wiped out as well.
What the hell is happening in that google script, and how do I insert this without everything blowing up?!?
Update:
Looks like for some reason safari didn't like the way I was adding the script. To fix this, I added bucket.innerHTML = '' below the debugger line and it worked great in Safari. Unfortunately, that caused FF 3.6 to do what safari was previously doing and nuke the DOM.
To make it even more complicated, it seems AdWords was rejecting these conversions or something, they don't show up on the reporting end when injected to the page.
My current approach is to use htaccess and a little string parsing to generate a page with nothing but the conversion snippet on it, and iFrame it in. I'll report back on that.

Perhaps it might be easier to insert the Google Ads via an iFrame?
Such as like this:
<iframe src="/documents/adsense.htm" width="728px" height="90px" frameborder="0" marginwidth ="0px" marginheight="0px" scrolling="no"></iframe>
iFrame contains:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Google Adsense</title>
<base target="_parent">
</head>
<body>
<!--insert Google Adsense Code Here-->
</body>
</html>
Google will still know and track the parent page.

Related

How to load third-party javascript tag asynchronously which has document.write

We give out a piece of javascript tags such as <script src="http://ours.com/some.js"></script> which site owners put on their site like http://example.com and in this javascript tag we want to dynamically include a third-party js such as which can have document.write in it, but of course if we try to include it by conventional method,
var script_tag = document.createElement('script');
script_tag.type = 'text/javascript';
script_tag.src="http://third-party.com/some.js";
document.getElementById('target').appendChild(script_tag);
we get a warning from browser,
Warning: A call to document.write() from an asynchronously-loaded
external script was ignored.
How do we get around this? Keep in mind, we don't really have control over third-party scripts so we can't change the logic in it. We are looking for some solution which can work across all browsers.
The problem with loading a script on a already loaded document (instead of having the browser ignore the document.write()) is that you would delete all existent HTML. See this example so you can understand exactly what's happening, or for more details look at a documentation page for the document.write() method.
While I know this might not be what you're expecting to get as an answer, I believe you are out of luck since rewriting the script is not an option.
This appears to be a similar question with similar replies.
You can support script injection the correct way by intercepting calls to document.write in this way:
document.writeText = document.write;
document.write = function(parameter) {
if (!parameter) return;
var scriptPattern = /<script.*?src=['|"](.*?)['|"]/;
if (scriptPattern.test(parameter)) {
var srcAttribute = scriptPattern.exec(parameter)[1];
var script = document.createElement('script');
script.src = srcAttribute;
document.head.appendChild(script);
}
else {
document.writeText(parameter);
}
};
Obviously this can be condensed down a bit further, but the variable names are included for clarity.
Source
How about instead of loading the script by appending a script element, you load the contents of the script URL with an AJAX call and then use eval() to run it in the global scope? Here's an example and I did test it to verify that it works:
<!DOCTYPE html>
<html>
<head>
<script>
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
window.eval(xmlhttp.responseText); //Indirect call to eval to execute in global scope (http://perfectionkills.com/global-eval-what-are-the-options/)
}
}
xmlhttp.open("GET", "https://third-party.com/test.js", false); //This is synchronous so that any document.write calls don't overwrite the entire page when they get called after the document is finished rendering. For all intents and purposes, this just loads the script like any other script, synchronously.
xmlhttp.send();
</script>
</head>
<body>
<div><h2>Hello World</h2></div>
</body>
</html>
And here are the contents I had in the test.js file:
document.write("This is a test...");
alert("...This is a test alert...");
console.log("...And a console message.");
I made the AJAX request for the script synchronous so that it would be loaded exactly as if it were a regular embedded script tag. If you run it asynchronously, and the script uses document.write after the page has been fully rendered, it clears the DOM and then writes to it... Kind of annoying actually. Lemme know if this works for you. :)
Document.write will not work from async script because document is already loaded when script starts working.
But you can do this:
document.body.innerHTML = document.body.innerHTML + '<h1>Some HTML</h1>';
Another procedure is to change the behavior of document.write() function.
Assume you have the main index.php file:
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
Hello<br>
<div id="target"></div>
<script>
document.write = function(input) {
document.body.innerHTML += input;
}
var doit = function() {
var script_tag = document.createElement('script');
script_tag.type = 'text/javascript';
script_tag.src="http://127.0.0.1:8080/testPlace/jsfile.js";
document.getElementById('target').appendChild(script_tag);
}
</script>
</body>
</html>
and the jsfile.js is like this:
document.write("OK MAN!");
now if you type doit() in the js browser console to execute that function (and the script do what you wrote) then the result would be:
Hello
OK MAN!
In which the html is like this:
<html><head>
<meta charset="utf-8">
</head>
<body>
Hello<br>
<div id="target"><script src="http://127.0.0.1:8080/testPlace/jsfile.js" type="text/javascript"></script></div>
<script>
//That Script which here I removed it to take less space in answer
</script>
OK MAN!</body>
</html>
What is the 3rd party javascript file?
If it's Google Maps JavaScript API v3 then make sure you include "&callback=your_init_funct" in the script URL. Then it will call 'your_init_funct' once the maps library is loaded so that you can begin displaying the map.
Another solution would be bezen.domwrite.js which is available here: http://bezen.org/javascript/index.html
Demo: http://bezen.org/javascript/test/test-domwrite.html
Yes, document.write can't be called from an asynchronously loaded script, because it's detached from the document, so it can't write to it.
You can see the approach used here for the google maps api to get around this problem. So, it is possible some of your 3rd party scripts that you haven't named, could have the similar callback pattern implemented.
https://developers.google.com/maps/documentation/javascript/examples/map-simple?hl=EN
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
async defer></script>
</body>
</html>

embed zippyshare player into a local html

I try to embed this zippyshare player
<script type="text/javascript">var zippywww="54";var zippyfile="JnIxIFUy";var zippytext="#000000";var zippyback="#e8e8e8";var zippyplay="#ff6600";var zippywidth=850;var zippyauto=false;var zippyvol=80;var zippywave = "#000000";var zippyborder = "#cccccc";</script><script type="text/javascript" src="http://api.zippyshare.com/api/embed_new.js"></script>
into a html file on my pc! When I do this and open it, it will show nothing!
Any idea to do this or why it don't work?
Thanks a lot
This is old but kind of interesting since their embed code didn't work out-of-the-box for me either.
Here's how I managed to embed the Zippyshare player into my html for anyone facing this same issue.
If you look at the embed code, there is this <script type="text/javascript" src="http://api.zippyshare.com/api/embed_new.js"></script> at the end of all the declared parameters. Copy that url http://api.zippyshare.com/api/embed_new.js into your browser and there's the iframe you are looking for... right?
This is what it looks like:
var a = navigator.userAgent||navigator.vendor||window.opera;
document.write("<iframe height=\"92\" width=\""+zippywidth+"\" frameBorder=\"0\" src=\""+window.location.protocol+"//api.zippyshare.com/api/jplayer_embed.jsp?key="+zippyfile+"&server=www"+zippywww+"&width="+zippywidth+"\"></iframe>");
Somehow, however, your webpage never receives this. So I copied that part and pasted into my html code, replacing the zippyshare script call and modifying it a bit (replacing escape characters with single quotes). So my html now looks like this:
<body>
<script type="text/javascript">
var zippywww="20";
var zippyfile="CyeL81Cn";
var zippytext="#000000";
var zippyback="#e8e8e8";
var zippyplay="#ff6600";
var zippywidth="100%";
var zippyauto=false;
var zippyvol=80;
var zippywave = "#000000";
var zippyborder = "#cccccc";
var a = navigator.userAgent||navigator.vendor||window.opera;
document.write("<iframe height='92' width='"+zippywidth+"' frameBorder='0' src='http://api.zippyshare.com/api/jplayer_embed.jsp?key="+zippyfile+"&server=www"+zippywww+"&width="+zippywidth+"' allowfullscreen></iframe>");
</script>
<!--script type="text/javascript" src="//api.zippyshare.com/api/embed_new.js"></script-->
</body>
It works, BUT I still wouldn't recommend it as it defeats the core purpose of having an api call. So this is not as much an answer as it is a very temporary fix :) while you figure it out or while Zippyshare figures out what to do with all those unused customization parameters you specify.

Google Adwords Conversion Tracking: Missing <noscript> tag

I am trying to implement the Google AdWords Conversion Tracking on a "Thank you" page after form submission. I am using the Google Tag Assistant in Chrome to test my tags.
Here is my code. Of course the values for the conversion_label and conversion_id are changed to the values given by Google.
<script type="text/javascript">
/* <![CDATA[ */

 var google_conversion_id = 123456789;

 var google_conversion_language = "en";

 var google_conversion_format = "2";

 var google_conversion_color = "ffffff";
var google_conversion_label = "AAAAAAAAAAAAAAAAAAA";
var google_remarketing_only = false;
var google_conversion_value = 0;
/* ]]> */
</script>
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display: inline">
<img height="1" width="1" style="border-style:none;" alt="" src="http://www.googleadservices.com/pagead/conversion/123456789/?label=AAAAAAAAAAAAAAAAAAA&guid=ON&script=0"/>
</div>
</noscript>
However, I get this error when checking the tag in Google Tag Assistant: Missing <noscript> tag.
The <noscript> tag is there, and present when I go into the source code. Yet I am still getting this error. I tried putting that <noscript> tag in many places, without any luck.
The manual doesn't give any further information on this error.
Also, does this affect the tracking conversion ?
Any help appreciated. Thanks
The noscript bit is only required for browsers which do not have javascript enabled (this is a very small number of users these days) - if the browser has javascript enabled it will execute the javascript as normal.
Sometimes the tag assistant gets confused though (particularly if there are DOM or script errors elsewhere on the page it is checking) - that snippet you pasted looks ok to me, and a test in jsbin.com suggests everything is fine.

Google +1 Button script not loading in local html file

I'm playing around with the new Google +1 button and I've attempted to set up a simple demo of it.
This is my code:
<html>
<head>
<title>Plus One</title>
</head>
<body>
<!-- Place this tag where you want the +1 button to render -->
<g:plusone callback="plus_one_callback" href="http://www.testurl.com/"></g:plusone>
<!-- Place this tag after the last plusone tag -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
function plus_one_callback(){
alert('callback');
}
</script>
</body>
</html>
However it does not render the button and there is no error message in my console.
Here is a screengrab of my firebug net panel:
Anyone know why this happens?
It won't work because as of Firefox 3 you can't run external JS scripts locally. Or to be more exact, you'll run into problems when firefox sees "file://" in the url. This question was also answered here. It probably would work if you used another browser.
If you really need this kind of stuff to work locally, however, there is a solution. You can install WAMP or XAMPP to run a local server.

jQuery works on jsFiddle but not in a live page

THE QUESTION
Interesting one that probably has a simple solution. With the help of #jessegavin I've added a jQuery function to my page that controls the playback of HTML5 audio elements on the page. The code is beautiful and works correctly on a jsFiddle, but not when put into the context of my page.
I've thrown time to the wind and methodically stepped through this to try and isolate my mistake, but with no avail. Really, I went Aristotle on this one and applied the scientific method. Please forgive me for the heft of this question. It's really my last resort.
THE NITTY GRITTY
Here are my findings: All the JavaScript functions for the page work correctly in context of the jsFiddle. After specifically adding the functions one at a time I can say that they each work appropriately, and that all except for the HTML5 audio playback work on both the jsFiddle and the live page. That is to say ONLY the HTML5 audio playback is not working on the live page.
All the HTML is 100% validated, all the CSS is 100% validated. Both groups are code are added into the jsFiddle in their entirety.
The page heading loads (in this order) an external CSS document, jQuery 1.5.1 and jQuery UI 1.8.8 (same on jsFiddle, except for UI, which is 1.8.9) via Google's onload command, an external JavaScript document (where ALL functions for the site reside), and finally a Google Analytics function.
The JavaScript is wrapped in a document ready framework.
My guess is that the discrepancy lies somewhere in the head, but I cant imagine what exactly it is. All the external links work correctly, evidenced by the JavaScript functions working correctly (except for the new audio controller).
THE POST SCRIPT
P.S.- Only works in Chrome and Safari as of yet.. The server I'm hosting the two audio files off of doesn't have the correct ht-access file declaring OGG as a correct MIME type. I'll start a question for that too.
RESOURCES
jsFiddle: http://jsfiddle.net/66FwR/3/
HTML (heading only, body is in jsFiddle)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8>
<meta name="description" content="Fernando Garibay- Producer, Songwriter, Artist, Multi-Instrumentalist, and Programmer" />
<meta name="keywords" content="Fernando Garibay, Music, Producer, Songwriter, Artist, Mutli-Instrumentalist, Programmer." />
<title>Fernando Garibay - Music</title>
<link rel="icon" type="image/png" href="http://www.fernandogaribay.com/favicon.ico" />
<link href="../styles/fernando.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="https://www.google.com/jsapi?key=ABQIAAAAqfg-jHFfaMB9PWES0K_8ChTCwkclEZER8BG2IP57SKkFV1O9hxSZkzKYPDs-3mbhEluKXjbKUAB7sQ"></script>
<script type="text/javascript">
  google.load("jquery", "1.5.1");
  google.load("jqueryui", "1.8.8");
</script>
<script type="text/javascript" src="../scripts/fernando.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<!--Copyright 2011, Fernando Garibay, Inc-->
<!--Developed by Minimal +-->
</head>
<body onload="message()">
JavaScript (the function that works on jsFiddle, but not in a live page)
$(function() {
$(".playback").click(function(e) {
e.preventDefault();
var song = $(this).next('audio').get(0);
if (song.paused)
song.play();
else
song.pause();
});
});
I see two JavaScript errors on your live page (in both Chrome and Firefox):
Uncaught TypeError: Object [object Object] has no method 'fancybox'
Uncaught ReferenceError: message is not defined
You reference fancybox() in fernando.js, and message in the <body onload="message()">. Those errors are most likely stopping your audio control code from running.
The URL is http://fiddle.jshell.net/66FwR/3/show/ look at that.
It includes jQuery UI too. You could copy the source and use that.

Categories