I'm creating a JS widget and first part is to add script with javascript, something like this (example from google analytics):
(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);
})();
How to test it with jasmine (using fixtures)?
For setting up HTML fixtures in my specs, I wrote jasmine-fixture. With it, you can do stuff like this:
var $foo, $input;
beforeEach(function(){
$foo = affix('.foo');
# appends to the DOM <div class="foo"></div>
$input = $foo.affix('input[id="name"][value="Jim"]');
# appends <input id="name" value="Jim"/> beneath the .foo div
And afterEach, it'll clean up after you.
For expectations about the state of the DOM, I use jasmine-jquery. It offers a ton of matchers like the one below:
it('is named Jim', function(){
expect($input).toHaveValue("Jim");
});
I suppose you could perform your action, then check the href on the first script tag like so:
function addGA(){
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);
};
Jasmine spec:
var href = 'http://www.google-analytics.com/ga.js';
expect(document.getElementsByTagName('script')[0].href).not.toEqual(href);
addGa();
expect(document.getElementsByTagName('script')[0].href).toEqual(href);
Would be interested in hearing a better method, though. Checking the DOM with Jasmine always feels a little hacky.
For heavy DOM testing with Jasmine you can use Jasmine Headless WebKit.
Related
I'm developing some functionality that puts some adds on the my clients page.
I just give them some javascript that they have to add to their page.
That javascript as an identifier to the id of the add (for constructing purpose).
The javascript for every add is like this:
var _adds = _adds || [];
_adds.push(['ID_OF_THE_ADD_XXXXX']);
(function() {
var script = document.createElement('script');
script.src = ('https:' == document.location.protocol ? 'https://ssl' :
'http://www') + '.myswebsite.com/myjs.js';
script.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(script);
})();
So, the hard part is that myjs.js is added many times to the head of client's page.
I already tried to declare some variable com myjs.js and check that var here but without success because everything is async.
Is there a way to not duplicate this?
Thanks in advance.
okay just got that before loading the prev script it is getting executed again so try this.
var _adds = _adds || [];
_adds.push(['ID_OF_THE_ADD_XXXXX']);
(function() {
if(typeof window.checker ==='undefined'){
window.checker = true;
var script = document.createElement('script');
script.src = ('https:' == document.location.protocol ? 'https://ssl' :
'http://www') + '.myswebsite.com/myjs.js';
script.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(script);
}
})();
I read somewhere that placing google analytics tracking code in seperate file is not recommended but I have no idea how to use it for my website (there are .php files and .tpl files and if I tried to put it almost everywhere and there was an error or it didn`t track the visitors).
Could anyone tell me which code I should put into separate .js file and in .tpl file so at least the basic functions would work? Thanks a lot!
This is the cleanest (using a anonymous auto-executing function):
(function() {
var _gaq = window._gaq = window._gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
_gaq.push(['_trackPageview']);
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);
})();
Then reference in either your head or before end of body via:
<script type="text/javascript" src="YOUR_GA_CODE_LOCATION.js"></script>
you can write google analytics code in separate js file and include that js and call its function -
Suppose, following code is written in mygoogle.js
function loadMyGoogle()
window._gaq = window._gaq || [];
window._gaq.push([ '_setAccount',
'setaccounthere']);
(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);
})();
}
then in your php files in header -
<head>
<include script="mygoogle.js">
</head>
In onload function of body tag -
function onload(){
loadMyGoogle();
}
I hope you know how you can set onload event in body tag
Do not put GA code in .js file instead include html page.
Steps:
1) Open notepad and paste GA code there.
2) Save it as HTML page
3) Include that html before end of head tag
I have been building script tag using javascript.when I use this script to load the three other scripts,the script is not loading in order.I want jquery.min.js to get loaded first. So I have used that as the first parameter. But it is not getting loaded at first. so I have been caught up with reference error. Can anyone tell me what mistake I have done in this code. My code is here
<script type="text/javascript">
(function (a, b, c) {
var g = document.createElement('script');
g.type = 'text/javascript';
g.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://') + a;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(g, s);
var g = document.createElement('script');
g.type = 'text/javascript';
g.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + b;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(g, s);
var g = document.createElement('script');
g.type = 'text/javascript';
g.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + c;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(g, s);
})('ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', '.example.com/js/script.js', '.example.com/js/form.js');
</script>
Use require.js for dynamic script loading.It will work.Also, try to use jquery.js above the website rather generate using script.
After my studing around this toppics, I updated for who visit to this question later.
For most of the browsers (IE9, Firefox, Chrome, Safari, ...) except Opera (12.16), dynamic script injection into DOM will load script asynchronously.
So this code:
function loadScript(src) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
}
loadScript('script1.js');
loadScript('script2.js');
loadScript('script3.js');
is almost equivalent to:
<script src="script1.js" async></script>
<script src="script2.js" async></script>
<script src="script3.js" async></script>
But if the async flag is set to false explicitly like:
function loadScript(src) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
script.async = false;
}
then the scripts will be loaded in order synchronously.
So the very short answer for this question is that g.async = false, but still I also recommend to use some framework and that is the best answer.
Try this: http://jsfiddle.net/DRCzN/
~~~~ original answer ~~~~~~
Dynamic script insertion (createElement('script') then insertBefore() or even insertAfter()) will load each script asynchronously.
So with your current script, the arrival of those script to the browser heavily depends on the network status.
If you want keep the dependency of these scripts, you can use some script loader such as $script, head.js or Require.js.
EDIT: I like Jonathan's solution, and here is a little improvement using $.getScript().
if script.js and form.js are independent of each other
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
(function(scripts) {
var protocol = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://www.');
$.each(scripts, function(i, s) {
$.getScript(protocol + s);
});
})(['.example.com/js/script.js', '.example.com/js/form.js']);
</script>
if form.js depneds on script.js
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
(function(scripts) {
var protocol = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://www.');
$.getScript(protocol + scripts[0], function() {
$.getScript(protocol + scripts[1]);
});
})(['.example.com/js/script.js', '.example.com/js/form.js']);
</script>
It's close, but use insertAfter, and remember to increase the index for each script.
var s = document.getElementsByTagName('script')[0];
g.parentNode.insertBefore(s, g.nextSibling);
...
var s = document.getElementsByTagName('script')[1];
g.parentNode.insertBefore(s, g.nextSibling);
...
var s = document.getElementsByTagName('script')[2];
g.parentNode.insertBefore(s, g.nextSibling);
Here's another example. This one uses an array of scripts to add, reverses them and then inserts after the current script tag.
EDIT: Can you get away with loading jQuery directly, as below. Using // a the start will make the resource load under the current protocol.
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
(function (scripts) {
var protocol = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://www.'),
thisScript = document.getElementsByTagName('script')[0];
function createScriptTag(element, index, array) {
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = protocol + element;
thisScript.parentNode.insertBefore(newScript, thisScript.nextSibling);
};
(scripts || []).reverse().forEach(createScriptTag);
})(['example.com/js/script.js', 'example.com/js/form.js']);
</script>
Here is another method of solving this problem :
<script type="text/javascript">
window.onload = function () {
"use strict";
function js(n) {
var s = document.createElement('script');
s.setAttribute("type", "text/javascript");
s.setAttribute("src", n);
document.getElementsByTagName("head")[0].appendChild(s);
}
js("http://requirejs.org/docs/release/2.1.8/minified/require.js");
js("http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js");
js("http://www.example.com/form.js");
js("http://www.example.com/script.js");
};
</script>
This can also be used rather than the code explained in question.
i want to only trigger a page hit once a function has been triggered. so can i do the following?
<script type="text/javascript">
function gaCodeParser(parseGAcode){
if(parseGAcode == 'triggerGAcode'){
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-xxxxxx-xx']);
_gaq.push(['_trackPageview', '/success-page']);
(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);
})();
}
else{
//do nothing
}
}
</script>
Why do you want to capture that ? google analytics will anyway give you efficient metrics like unique views, unique visitors and so on, if you try to fiddle around thier code you will only loose metrics provided by GA. if you still want to go ahead and fork what is given by GA you can still do so but please dont expect GA to give you all metrics.
I made a helper for my javascript in order to track some ajax events, here's a short version of what it's set up to be
analytics:{
active: false,
gaq: null,
init: function(gaq){
this.active = true;
this.gaq = gaq;
$('a[href^=\"http://\"]').live('click', function() {
helper.analytics.trackPageview('/outgoing/' + $(this).attr('href'));
return true;
});
},
trackPageview: function(page){
if(this.active === false){
return;
}
this.gaq.push(['_trackPageview',page]);
}
},
And I have the common google analytics setup
<script type="text/javascript">
var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-xxxxxxxx-1']);
_gaq.push(['_setDomainName', '.example.com']);
_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);
})();
$(document).ready( function() {
helper.analytics.init(_gaq);
});
</script>
However in the console logging _gaq results in an object. logging helper.analytics.gaq results in an array, whith new pageviews appended, but the pageview is not being tracked in google analytics.
Why isn't _gaq being passed to the helper by reference?
When creating the script tag, the ga snippet sets the async attribute to true. Therefore, it'll load independently from the body. You'll need to bind an event handler to the ga script tag's onload event. Something like so:
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.onload = function(){
herlper.analytics.init(_gaq);
};
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);
})();
I've not tested this, but I think it might work.
Do you see any syntax errors either in Crome dev tools console or Firefox & firebug?
You've got a '." after the initial script tag.