Many banner companies are using dynamic javascript loading to insert their banners in a website. Most of these companies grew big before the Ajax term was coined and recognized as the future technology of the web. So the scripts they are using assume the page is loading while the script is inserted; they use document.write() to add html to the page. As many of you might know, using document.write on an already loaded page will clear all it’s html and leave you with a white page containing only the banner. In this week’s snippet I’ll show you how to work around this.
The key of the solution is replacing document.write by a custom function. We assume that a banner is put in an html element that contains nothing else. The html element will have an id specified in the banners struct as below. For this example we are using the doubleclick.net url format.
banners = {
ord : Math.floor(Math.random() * 10000000000000000),
tile : 1,
url : "http://ad.nl.doubleclick.net/adj/dqa.sdu.nbdonline.nl/ros;kw=;dcopt=ist;",
topbanner : {
size : "728x90"
},
skyscraper : {
size : "120x600;"
},
squarebanner : {
size : "336x280;"
},
init : ["squarebanner", "skyscraper", "topbanner"]
};
This struct specifies three banners which are put in html elements with id’s squarebanner, skyscraper and topbanner. First lets set up the function that dynamically inserts javascript elements (if you’re using Javeline Platform the function is jpf.include()):
function include(sourceFile, type){
var head = document.getElementsByTagName("head")[0];
var elScript = document.createElement("script");
if (type)
elScript.setAttribute("_jpf_type", type);
elScript.src = sourceFile;
head.appendChild(elScript);
}
Now we create a function that loads a banner based on it’s name. We clear all script tags that have the type ‘banner’ to keep the DOM clean. We record the last banner that was loaded. That’s used later in the document.write function.
function loadBanner(type){
var banner = banners[type];
banners.last = banner;
banner.html = document.getElementById(type);
banner.load = true;
if (!banner.tile)
banner.tile = banners.tile++;
var s = document.getElementsByTagName("script");
for (var i = 0; i < s.length; i++) {
if (s[i].getAttribute("_jpf_type") == "banner")
s[i].parentNode.removeChild(s[i]);
}
include(banner.url + 'tile=' + (banner.tile) + ";sz=" + banner.size
+ ';ord=' + banners.ord + '?', "banner");
}
Last we override the document.write function. We first clear the contents of the html element. Then we find all the script tags inside the string and include them in an Ajax-safe way. Then we insert the remaining HTML in the html element. Because we cannot parallelize this process we check if it has finished by looking for a noscript tag or an href attribute in the html and load the next banner in queue, if any.
document.write = function(str){
if (!banners.last.html)
return;
if (banners.last.load) {
banners.last.html.innerHTML = "";
banners.last.load = false;
}
str = str.replace(/.*?/g, function(m, src){
include(src, “banner”);
});
if (str) {
banners.last.html.innerHTML = str;
if ((str.indexOf(”NOSCRIPT”) > -1
|| str.indexOf(”href”) > -1) && !banners.last.inited) {
banners.last.inited = true;
if (banners.init.length)
loadBanner(banners.init.pop());
}
}
}
Now all you need to do is start the init process:
loadBanner(banners.init.pop());
Anywhere in your ajax application you can reload a banner by calling loadBanner(name).