Chrome extensions - modify script before execution - javascript

I'm kinda new to this chrome-extensions stuff, and i'm trying to modify a script before it is executed.
Example:
<script type="text/javascript">
function() {
var count = 10;
countDown = setInterval(function() {
if(count == 0) {
// do Stuff
}
count--;
}, 1000);
}
</script>
My goal is to either remove this script from the site (before it is executed) and inject my own (i already did the injection-part) or modify it (for example set count to 20 so it takes 20 seconds).
I've already tried a lot of things but i just can't find a good way.
Hope you can help me :)

It's going to be pretty difficult to hijack that part on the fly, but at least you can stop the timer.
All you need to do is to call
clearInterval(countDown);
..in the right context.
At this point the extension architecture and the concept of isolated worlds come into play.
The only part of the extension that can interact with the webpage is a content script. But then, the content script lives in a separate context:
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.
But you need to access the page's JavaScript. There's a way, by injecting your code into the page as a <script> tag:
var script = document.createElement('script');
script.textContent = "clearInterval(countDown);";
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

Related

Can you execute contained JavaScript in browsers?

I want to be able to run JavaScript on my webpage and guarantee that it can be stopped cleanly without causing problems. You could think of it as running JavaScript as if it was contained in an iFrame but allow it to modify and interact with the root DOM. That way if I remove the iFrame, the JS dies.
Use Case/Justification
I want to turn any webpage into a weird mutant SPA. That means taking the traditional HTML, CSS, and JavaScript and then handling page switching myself. To propperly switch pages avoiding artifacts from previously executing JS I'd need to make sure one page's JS doesn't interact with the next page's JS. Ideally, to switch a page it would follow this general formula:
Load HTML and CSS with a framework like Ember.js
Load all linked JavaScript in a contained environment but with the ability to modify the root DOM
When the user clicks a link, stop all running JavaScript and return to step 1.
My Thoughts
I've run tests actually loading a webpage in a full-screen iframe (like this) which achieves the level of containment that I want when executing the JavaScript, but it has serious performance penalties. I want the contained JavaScript, with a minimal performance penalty.
One thought I had was after downloading JavaScript, replacing the actual code dynamically. I would change the code to instead of referencing the Window, referencing the Window.parent.
I'm not attached to the idea of using iFrames, but it just seems like it is the closest thing to a "container" that you can get in JavaScript/the browser. I'd love alternatives.
Related?
github.com/codeschool/javascript-sandbox
instantclick.io/
shadow DOM?
Mini-Followup:
Would it be feasible to build an app like this which would allow for proper handling of both JS life cycles and page switches?
You can't unload a script once it has been loaded. But you can encapsulate some script in an object, and create or destroy this object.
For instance:
var Robot = function(){
return{
sayHello : function(){
alert("Hello!");
},
doSomethingElse : function(){
alert("I'm doing something else");
}
}
}
robot = new Robot();
robot.sayHello(); // Actually alerts "Hello!"
robot = null; // the robot is destroyed.
In your case, if you load a script via ajax, say this piece of script in an object :
{
sayHello : function(){
alert("Hello!");
},
doSomethingElse : function(){
alert("I'm doing something else");
}
}
you can then encapsulate this script in a function :
var Robot = null,
robot = null;
$.get('scriptURL', function(ajaxedScriptObject){
Robot = function(){ return ajaxedScriptObject; };
createRobot();
})
function createRobot(){
robot = new Robot();
sayHello();
destroyRobot();
}
function sayHello(){
robot.sayHello(); // Should alert "Hello!" :)
}
function destroyRobot(){
robot = null;
}

Can't connect API to Chrome extension

I am developing chrome extension. I want to connect some API to current tab after click on button in popup.html. I use this code in popup.js:
$('button').click(function() {
chrome.tabs.executeScript({
file: 'js/ymaps.js'
}, function() {});
});
In ymaps.js I use following code to connect API to current tab:
var script = document.createElement('script');
script.src = "http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU";
document.getElementsByTagName('head')[0].appendChild(script);
This API is needed to use Yandex Maps. So, after that code I create <div> where map should be placed:
$('body').append('<div id="ymapsbox"></div>');
And this simple code only loads map to created <div>:
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
I think, everything is clear, and if you are still reading, I'll explain what is the problem.
When I click on button in my popup.html I get in Chrome's console Uncaught ReferenceError: ymaps is not defined. Seems like api library isn't connected. BUT! When I manually type in console ymaps - I get list of available methods, so library is connected. So why when I call ymaps-object from executed .js-file I get such an error?
UPD: I also tried to wrap ymaps.ready(init) in $(document).ready() function:
$(document).ready(function() {
ymaps.ready(init);
})
But error is still appearing.
Man below said that api library maybe isn't loaded yet. But this code produces error too.
setTimeout(function() {
ymaps.ready(init);
}, 1500);
I even tried to do such a way...
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
if (changeInfo.status == "complete") {
chrome.tabs.executeScript({
file: 'js/gmm/yandexmaps.js'
});
}
});
ymaps is not defined because you're trying to use it in the content script, while the library is loaded in the context of the page (via the <script> tag).
Usually, you can solve the problem by loading the library as a content script, e.g.
chrome.tabs.executeScript({
file: 'library.js'
}, function() {
chrome.tabs.executeScript({
file: 'yourscript.js'
});
});
However, this will not solve your problem, because your library loads more external scripts in <script> tags. Consequently, part of the library is only visible to scripts within the web page (and not to the content script, because of the separate script execution environments).
Solution 1: Intercept <script> tags and run them as a content script.
Get scriptTagContext.js from https://github.com/Rob--W/chrome-api/tree/master/scriptTagContext, and load it before your other content scripts. This module solves your problem by changing the execution environment of <script> (created within the content script) to the content script.
chrome.tabs.executeScript({
file: 'scriptTagContext.js'
}, function() {
chrome.tabs.executeScript({
file: 'js/ymaps.js'
});
});
See Rob--W/chrome-api/scriptTagContext/README.md for documentation.
See the first revision of this answer for the explanation of the concept behind the solution.
Solution 2: Run in the page's context
If you -somehow- do not want to use the previous solution, then there's another option to get the code to run. I strongly recommend against this method, because it might (and will) cause conflicts in other pages. Nevertheless, for completeness:
Run all code in the context of the page, by inserting the content scripts via <script> tags in the page (or at least, the parts of the extension that use the external library). This will only work if you do not use any of the Chrome extension APIs, because your scripts will effectively run with the limited privileges of the web page.
For example, the code from your question would be restructed as follows:
var script = document.createElement('script');
script.src = "http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU";
script.onload = function() {
var script = document.createElement('script');
script.textContent = '(' + function() {
// Runs in the context of your page
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
} + ')()';
document.head.appendChild(script);
};
document.head.appendChild(script);
This is just one of the many ways to switch the execution context of your script to the page. Read Building a Chrome Extension - Inject code in a page using a Content script to learn more about the other possible options.
This is not a timing issue, rather an "execution environment"-related issue.
You inject the script into the web-page's JS context (inserting the script tag into head), but try to call ymaps from the content script's JS context. Yet, content-scripts "live" in an isolated world and have no access to the JS context of the web-page (take a look at the docs).
EDIT (thx to Rob's comment)
Usually, you are able to bundle a copy of the library and inject it as a content script as well. In your perticular case, this won't help either, since the library itself inserts script tags into to load dependencies.
Possible solutions:
Depending on your exact requirements, you could:
Instead of inserting the map into the web-page, you could display (and let the user interact with) it in a popup window or new tab. You will provide an HTML file to be loaded in this new window/tab containing the library (either referencing a bundled copy of the file or using a CDN after relaxing the default Content Security Policy - the former is the recommended way).
Modify the external library (i.e. to eliminate insertion of script tags). I would advise against it, since this method introduces additional maintainance "costs" (e.g. you need to repeat the process every time the library is updated).
Inject all code into the web-page's context.
Possible pitfall: Mess up the web-pages JS, e.g. overwriting already defined variables/functions.
Also, this method will become increasingly complex if you need to interact with chrome.* APIs (which will not be available to the web-page's JS context, so you'll need to device a proprietary message passing mechanism, e.g. using custom events).
Yet, if you only need to execute some simple initialization code, this is a viable alternative:
E.g.:
ymaps.js:
function initMap() {
ymaps.ready(init);//Waits DOM loaded and run function
var myMap;
function init() {
myMap = new ymaps.Map("ymapsbox", {
center: [55.76, 37.64],
zoom: 7
});
}
}
$('body').append('<div id="ymapsbox"></div>');
var script1 = document.createElement('script');
script1.src = 'http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU';
script1.addEventListener('load', function() {
var script2 = document.createElement('script');
var script2.textContent = '(' + initMap + ')()';
document.head.appendChild(script2);
});
document.head.appendChild(script1);
Rob already pointed to this great resource on the subject:
Building a Chrome Extension - Inject code in a page using a Content script
There is a much easier solutioin from Yandex itself.
// div-container of the map
<div id="YMapsID" style="width: 450px; height: 350px;"></div>
<script type="text/javascript">
var myMap;
function init (ymaps) {
myMap = new ymaps.Map("YMapsID", {
center: [55.87, 37.66],
zoom: 10
});
...
}
</script>
// Just after API is loaded the function init will be invoked
// On that moment the container will be ready for usage
<script src="https://...?load=package.full&lang=ru_RU&onload=init">
Update
To work this properly you must be sure that init has been ready to the moment of Yandex-scirpt is loaded. This is possible in the following ways.
You place init on the html page.
You initiate loading Yandex-script from the same script where init is placed.
You create a dispatcher on the html page which catches the ready events from both components.
And you also need to check that your container is created to the moment of Yandex-script is loaded.
Update 2
Sometimes it happens that init script is loaded later than Yandex-lib. In this case it is worth checking:
if(typeof ymaps !== 'undefined' && typeof ymaps.Map !== 'undefined') {
initMap();
}
Also I came across a problem with positioning of the map canvas, when it is shifted in respect to the container. This may happen, for example, when the container is in a fading modal window. In this case the best is to invoke a window resize event:
$('#modal').on('shown.bs.modal', function (e) {
window.dispatchEvent(new Event('resize'));
});

Warning: A call to document.write() from an asynchronously-loaded external script was ignored. How is this fixed?

In my Ruby on Rails application I am using the Facebox plugin for an Ajax pop up window. I have 2 pages called add_retail_stores/new.html.erb and add_retail_stores/new.js. The new.js page inherits all elements from the new.html.erb page so it looks exactly alike. I have a Google map script on the HTML page that works as it should. But the new.js page that pops up on my different page called add_store_prices.html.erb page(<%= link_to add_retail_store_path, :remote => true %>)
I get the error:
Warning: A call to document.write() from an asynchronously-loaded external script was ignored.
Source File: http://localhost:3000/add_store_prices
Line: 0
I believe because it's trying to go through 2 functions/scripts. The first one for the Facebox and then the Google script. Anyone know how to handle this error?
EDIT:
I believe the Facebox plugin is using document.write but I am not sure where, perhaps in one of these 2 lines on my page?
new.js:
$.facebox('<%= escape_javascript(render :template => 'business_retail_stores/new.html') %>')
$('#facebox form').data('remote','true');
Don't use document.write. The script is being loaded asynchronously, which means it's detached from the document parsing state. There is quite literally NO WAY for the JS engine to know WHERE the document.write should be executed in the page.
The external script could load instantaneously and the document.write executes where the <script src="..."> tag is, or it could hit a net.burp and load an hour later, which means the document.write gets tagged at the end of the page. It's quite literally a race condition, so JS engines will ignore document.writes from scripts loaded asynchronously.
Convert the document.write to use regular DOM operations, guarded by a document.onload type handler.
If you have access to the .js file in question, your best solution is going to be to modify the "document.write()" method and replace it with whatever makes sense in order to distribute the content contained within.
The reasons for this are very well described above.
If you are using document.write to write html tags to the page:
document.write("<script src=...></script>");
or
document.write("<img href=... />");
Consider using the same sort of asynchronous format you've already been using:
// Add/Remove/Sugar these components to taste
script = document.createElement("script");
script.onload = function () { namespaced.func.init(); };
script.src = "http://...";
document.getElementsByTagName("script")[0].parentNode.appendChild(script);
If you're looking to append DOM elements that are for the user to see and interact with, then you're better off either:
a) Grabbing a specific containter (section/div) by id, and appending your content:
document.getElementById("price").innerHTML = "<span>$39.95</span>";
b) Building content off-DOM and injecting it into your container:
var frag = document.createDocumentFragment(),
span = document.createElement("span");
span.innerText = "39.95";
frag.appendChild(span);
document.getElementById("price").appendChild(frag);
Again, Sugar to your liking.
If you DON'T have access to mod this second .js file, I'd suggest taking it up with them.
I had the same problem loading google maps with the places library. I temporarily override the write function to create a new script element in the head.
(function() {
var docWrite = document.write;
document.write = function(text) {
var res = /^<script[^>]*src="([^"]*)"[^>]*><\/script>$/.exec(text);
if (res) {
console.log("Adding script " + res[1]);
var head = document.getElementsByTagName('head')[0];
var script = document.createElement("script");
script.src = res[1];
head.appendChild(script);
} else {
docWrite(text);
}
}
})();
Now all I have to do to load a script asynchronously is
document.write('<script src="http://maps.googleapis.com/maps/api/js?libraries=places"></script>');

JavaScript: How to download JS asynchronously?

On my web site, I'm trying to accomplishes the fastest page load as possible.
I've noticed that it appears my JavaScript are not loading asynchronously. Picture linked below.
alt text http://img249.imageshack.us/img249/2452/jsasynch2.png
How my web site works is that it needs to load two external JavaScript files:
Google Maps v3 JavaScript, and
JQuery JavaScript
Then, I have inline JavaScript within the HTML that cannot be executed until those two files above are downloaded.
Once it loads these external javascript files, it then, and only then, can dynamically render the page. The reason why my page can't load until both Google Maps and JQuery are loaded is that - my page, based on the geolocation (using Gmaps) of the user will then display the page based on where they are located (e.g. New York, San Francisco, etc). Meaning, two people in different cities viewing my site will see different frontpages.
Question: How can I get my JavaScript files to download asynchronously so that my overall page load time is quickest?
UPDATE:
If I were to download, somehow, Google-maps and JQuery asynchronously, how would I create an event that would be fired once both Google-maps and JQuery have downloaded since my page has a hard dependency on those files to execute.
UPDATE 2
Even though there are 3 answers below, none still actually answer the problem I have. Any help would be greatly appreciated.
HTTP downloads are generally limited by browsers to two simultaneous downloads per domain. This is why some sites have the dynamic content on www.domain.tla and the images and javascript on static.domain.tla.
But browsers act slightly differently with scripts, while a script is downloading, however, the browser won't start any other downloads, even on different hostnames.
The standard solution is to move scripts to the bottom of the page, but there is a workaround that might or might not work for you: Insert the script DOM element using Javascript.
You could use something like this, which works pretty well in most browsers. It has some issues in IE6 at least, but I don't really have the time to investigate them.
var require = function (scripts, loadCallback) {
var length = scripts.length;
var first = document.getElementsByTagName("script")[0];
var parentNode = first.parentNode;
var loadedScripts = 0;
var script;
for (var i=0; i<length; i++) {
script = document.createElement("script");
script.async = true;
script.type = "text/javascript";
script.src = scripts[i];
script.onload = function () {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
};
script.onreadystatechange = function () {
if (script.readyState === "complete") {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
}
};
parentNode.insertBefore(script, first);
}
};
require([
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
"http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
"http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/yuiloader/yuiloader-min.js"
], function () {
console.log(jQuery);
console.log($);
console.log(YAHOO);
});
Someone asked me to comment on this thread, but that was before #lonut posted a response. #lonut's code is a very good solution, but I have some comments (critical and not so critical):
First, #lonut's code assumes that the scripts do NOT have load dependencies on the other scripts. This is a little hard to explain, so let's work with the simple example of jquery.min.js and prototype.js. Suppose we have a simple page that just loads these two scripts like this:
<script src="jquery.min.js"></script>
<script src="prototype.js"></script>
Remember - there's nothing else in the page - no other JavaScript code. If you load that page the two scripts get downloaded and everything's fine. Now, what happens if you remove the jquery.min.js script? If you get errors from prototype.js because it's trying to reference symbols defined in jquery.min.js, then prototype.js has a load dependency on jquery.min.js - you cannot load prototype.js unless jquery.min.js has already been loaded. If, however, you don't get any errors, then the two scripts can be loaded in any order you wish. Assuming you have no load dependencies between your external scripts, #lonut's code is great. If you do have load dependencies - it gets very hard and you should read Chapter 4 in Even Faster Web Sites.
Second, one problem with #lonut's code is some versions of Opera will call loadCallback twice (once from the onload handler and a second time from the onreadystatechange handler). Just add a flag to make sure loadCallback is only called once.
Third, most browsers today open more than 2 connections per hostname. See Roundup on Parallel Connections.
The LABjs dynamic script loader is designed specifically for this type of case. For instance, you might do:
$LAB
.script("googlemaps.js")
.script("jquery.js")
.wait(function(){
// yay, both googlemaps and jquery have been loaded, so do something!
});
If the situation was a little more complex, and you had some scripts that had dependencies on each other, as Steve Souders has mentioned, then you might do:
$LAB
.script("jquery.js")
.wait() // make sure jquery is executed first
.script("plugin.jquery.js")
.script("googlemaps.js")
.wait(function(){
// all scripts are ready to go!
});
In either case, LABjs will download all of the scripts ("jquery.js", "googlemaps.js", and "plugin.jquery.js") in parallel, as least up to the point the browser will allow. But by judicious use of the .wait() in the chain, LABjs will make sure they execute in the proper order. That is, if there's no .wait() in between the two scripts in the chain, they will each execute ASAP (meaning indeterminate order between tehm). If there's a .wait() in between two scripts in the chain, then the first script will execute before the second script, even though they loaded in parallel.
Here is how I've managed to load gmaps asynchronously on a jquery mobile:
First, you can load jquery (i.e. with the require function posted above by IonuČ› G. Stan)
Then you can make use of the callback param in gmaps to do the following:
<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
var require = function (scripts, loadCallback) {
var length = scripts.length;
var first = document.getElementsByTagName("script")[0];
var parentNode = first.parentNode;
var loadedScripts = 0;
var script;
for (var i=0; i<length; i++) {
script = document.createElement("script");
script.async = true;
script.type = "text/javascript";
script.src = scripts[i];
script.onload = function () {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
};
script.onreadystatechange = function () {
if (script.readyState === "complete") {
loadedScripts++;
if (loadedScripts === length) {
loadCallback();
}
}
};
parentNode.insertBefore(script, first);
}
};
require([
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",], function () {
$.ajax({
type: "GET",
url: 'http://maps.googleapis.com/maps/api/js?v=3&sensor=false&callback=setMyMap',
dataType: "script"
});
});
function setMyMap() {
console.log('your actions here');
var coords = new google.maps.LatLng(40.5439532,-3.6441775);
var mOptions = {
zoom: 8,
center: coords,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("gmap"), mOptions);
}
</script>
<div id="gmap" style="width:299px; height:299px"></div>
</body>
The point is load jquery async (whathever method you choose) and on that callback place a new async call to gmaps with your starting method in the callback param of the gmaps script string.
Hope it helps
Regardless what order they download in, the scripts should be parsed/executed in the order in which they occur on the page (unless you use DEFER).
So, you can put both Google Maps first in the head, THEN JQuery. Then, in the body of your page somewhere:
<script language="Javascript">
function InitPage() {
// Do stuff that relies on JQuery and Google, since this script should
// not execute until both have already loaded.
}
$(InitPage); // this won't execute until JQuery is ready
</script>
But this does have the disadvantage of blocking your other connections while loading the beginning of the page, which isn't so awesome for page performance.
Instead, you can keep JQuery in the HEAD, but load the Google scripts from the InitPage() function, using JQuery's Javascript-loading functionality rather than the Google JSAPI. Then start your rendering when that call-back function executes. Same as the above, but with this InitPage() function instead:
function InitPage() {
$.getScript('Google Maps Javascript URL', function() {
// Safe to start rendering now
});
Move your javascript includes (<script src="...) from the HEAD element to the end of your BODY element. Generally whatever is placed in the HEAD is loaded synchronously, whatever is placed in the BODY is loaded asynchronously. This is more or less true for script includes, however most browsers these days block everything below the script until it is loaded - hence why having scripts included at the bottom of the body is best practice.
Here is the YUI guildline for this which explains it in further detail:
http://developer.yahoo.net/blog/archives/2007/07/high_performanc_5.html
This is also the reason why stylesheets should be in the head, and javascript should be in the body. As we do not want to see our page turn from spaghetti to niceness while the styles load asynchronously, and we don't want to wait on our javascript while our page loads.
The objective you have in mind would be served by using requireJS. RequireJS downloads the js resources asynchronously. Its a very simple and useful library to implement. Please read more here. http://requirejs.org/

Alternate way to load javascript counter script

I am trying to load the statcounter script from my custom js file. The original script looks like this:
<html>
<head>...</head>
<body>
...
<script type="text/javascript">
var sc_project=11111111;
var sc_invisible=1;
var sc_partition=11111111;
var sc_click_stat=1;
var sc_security="11111111";
</script><script type="text/javascript" src="http://www.statcounter.com/counter/counter_xhtml.js"></script>
...
</body></html>
The code seems to set the variables, then loads the counter script which reads the values of the variables and does its job.
I'm trying to call the counter script like this:
// file: counters.js
function CounterFromStatCounter() {
sc_project=11111111;
sc_invisible=1;
sc_partition=11111111;
sc_click_stat=1;
sc_security="11111111";
var oHead = document.getElementsByTagName('HEAD').item(0);
var oScript= document.createElement("script");
oScript.type = "text/javascript";
oScript.src="http://www.statcounter.com/counter/counter_xhtml.js";
oHead.appendChild( oScript);
}
// main page
<html>
<head>
...
<script type="text/javascript" src="counters.js"></script>
...
</head>
<body>
...
<script type="text/javascript">
CounterFromStatCounter();
</script>
...
</body></html>
The code seems to work: the script element that references the statcounter script appears in the head section as it should, but no visits are recorded - this means that the variables set in my script cannot be accesed by the counter script.
What am I doing wrong?
You are doing a couple of things wrong.
1) You likely have not validated your code. Go to http://jslint.com and validate your JavaScript.
2) Do not write JavaScript into your HTML. That has a tendency to force all code bits into the global namespace, which is very likely to produce collisions with any other JavaScript code.
3) Only reference external JavaScript files directly prior to the closing body tag. Script interpretation blocks parallel downloads in IE.
Accomplish those three and then come back for more help.
var CounterFromStatCounter = function () {
var sc_project = 11111111,
sc_invisible = 1,
sc_partition = 11111111,
sc_click_stat = 1,
sc_security = "11111111",
oHead = document.getElementsByTagName('head').item(0),
oScript= document.createElement("script");
oScript.setAttribute("type", "text/javascript");
oScript.setAttribute("src", "http://www.statcounter.com/counter/counter_xhtml.js");
oHead.appendChild(oScript);
}
I have looked at the above code more closely and here are my thoughts:
1) That is how the code should look once beautified and reduced to a single var command in your function without any implied globals, except for the function name itself.
2) Dynamically created content from client-side code is destroyed each time the page loads at each user. So you will likely not want to write output using JavaScript as any means of providing a data reference point. I recommend doing this completely on the server side to be more efficient. If you must use JavaScript you will need to write to some intermediate data store, like a JSON, file that you connect to using the xmlHttpRequest object.
3) I would not recommend writing anything to the head of the document dynamically from the client-side due to different interpretations of the DOM between browsers and also once the head is loaded the browser has no reason to read it again for new information.
4) To be most efficient scripts should be in external files that referenced just before the closing body tag, because script interpretation blocks parallel downloads in IE. Putting scripts in the head is results in dramatically slower page loads in IE as a result.
5) I changed "HEAD" to "head" because JavaScript and XHTML are both case sensitive.
6) I also changed the way attributes are appended to your dynamically created script tag to use DOM methods. I don't know if this is the more correct method, but it is certainly more inline to the standards.
Define the variables globaly and write some js like below.
window.attachEvent('onload', function() {
document.write('<script type=text\/javascript src=blabla.com\/counter.js><\/sc' + 'ript>');
});
this should work in IE. For other other browsers implement addEventListener...

Categories