views:

207

answers:

6

Hello,

I am writing a simple counter, and I would like to make installation of this counter very simple for users. One of the simplest counter code (for users who install it) I ever see was Google Analytics Code

So I would like to store main code in a file and user who will install my counter will need just to set websiteID like this:

<html><head><title></title></head><body>
<script type="text/javascript" src="http://counterhost.lan/tm.js"&gt;
var websiteId = 'XXXXX';
</script>
</body></html>

Here is my code:

<script type="text/javascript" src="http://counterhost.lan/tm.js"&gt;
var page = _gat.init('new');
</script>

and this is my JS file:

(function() {
    var z = '_gat';
    var aa = function init(data) { alert(data); alert(z);};

    function na() {
     return new z.aa();
    }
    na();
})();

I tried to understand Google Analytics javascript code but I failed to do this. Can anyone suggest how can I specify variable between tags and then read it in anonymous function which is located in a javascript file ? Thanks.

A: 

I'm not entirely clear about what you're asking, but...

You can tag any HTML element with an id attribute, then use
document.getEntityById() to retrieve that specific element.

You can also give any HTML element user-defined attributes having names of your own choosing, then get and set them for that element within Javascript.

Loadmaster
Are you sure you answered the right question?
Crescent Fresh
+2  A: 

In your example, websiteId is a global variable. So it is accessible everywhere including anonymous functions unless there is a local variable with the same name

<script> var websiteId = "something"; </script>

Later in the page or included js file...

(function() {
    alert(websiteId); //this should work
})();
Chetan Sastry
Thanks for advice, I found mistake in my code, this will work< script type="text/javascript" >var websiteId = '11';< / script >< script type="text/javascript" src="http://counterhost.lan/tm.js">< / script >in my code websiteId was located inside script tag, which also has src attribute, so this does not work< script type="text/javascript" src="http://counterhost.lan/tm.js">var websiteId = '11';< / script >
Boris
A: 

I think you've got a bit confused with how JS objects are called.

z is a String, '_gat'. You can't call aa() on it because a String has no member called aa. aa is a standalone function stored in a local variable. Even if you did call aa(), it doesn't return anything, so using the new operator on its results is meaningless. new can only be called on constructor-functions.

I guess you mean something like:

var _gat= function() {

    // Private variable
    //
    var data= null;

    // Object to put in window._gat
    //
    return {

        // Set the private variable 
        //
        init: function(d) {
            data= d;
        }
    };
}();

Then calling _gat.init('foo') as in your second example would set the variable to website ID 'foo'. This works because the _gat object is the return {init: function() {...}} object defined inside the anonymous function, keeping a reference (a ‘closure’) on the hidden data variable.

bobince
+1  A: 

Can anyone suggest how can I specify variable between tags and then read it [...]

Not if your tag has both a SRC attribute and JS content.

<script type="text/javascript" src="http:/x.com/x.js"></script>

.. is different from,

<script type="text/javascript">
    var x = 1;
</script>

One framework that optionally adds JS variables to SCRIPT tags is Dojo. So if you're using Dojo you can add variables to the global djConfig hash by writing,

<script type="text/javascript" src="mxclientsystem/dojo/dojo.js"
    djConfig="
    usePlainJson: true,
    parseOnLoad: true
">
</script>

Dojo does this by running through the SCRIPT tags and evaluating the custom djConfig attribute.

This does not, however solve your problem.

You do really want two SCRIPT tags. One saying,

<script type="text/javascript">
    var websiteId = '123456';
</script>

which will set a global variable websiteId and a second one,

<script type="text/javascript" src="http:/x.com/myreporter.js"></script>

which can load from anywhere and read out the websiteId variable and, I assume, report it back.

Michiel Kalkman
+1  A: 

You can pass variables to an anonymous function like so:

(function(arg1, arg2, arg3) {
    alert(arg1);
    alert(arg2);
    alert(arg3);
})("let's", "go", "redsox");

// will alert "let's", then "go", then "redsox" :)
Bialecki
A: 

If you specify a src attribute as part of a script element, any code within the script element tags themselves will not be executed. However, you can add this functionality with the following code. I got this technique from Crockford (I believe it was him), where he uses it in of his talks on the unrelated topic of rendering performance and asynchronously loading scripts into a page to that end.

JavaScript:

(function() {
    // Using inner class example from bobince's answer
 var _gat = (function() {
     var data= null;

     return {
         init: function(d) {
          console.info("Configuration data: ", d);
             data = d;
         }
     }
 })();

 // Method 1: Extract configuration by ID (SEE FOOT NOTE)
 var config = document.getElementById("my-counter-apps-unique-and-long-to-avoid-collision-id").innerHTML;

 // Method 2: search all script tags for the script with the expected name
 var scripts = document.getElementsByTagName("script");

 for ( var i=0, l=scripts.length; i<l; ++i ) {
  if ( scripts[i].src = "some-script.js" ) {
   config = scripts[i].innerHTML;
   break;
  }
 }

 _gat.init( eval("(" +config+ ")") );
})();

HTML:

<script type="text/javascript" src="some-script.js" id="my-counter-apps-unique-and-long-to-avoid-collision-id">
 {some: "foo", config: "bar", settings: 123}
</script>

Both methods have their draw backs:

  1. Using a unique and non-colliding ID will make determining the proper script element more precise and faster; however, this is not valid HTML4/XHTML markup. In HTML5, you can define arbitrary attributes, so it wont be an issue at that time

  2. This method is valid HTML markup; however, the simple comparison that I have shown can be easily broken if your url is subject to change (e.g.: http vs https) and a more robust comparison method may be in order

A note on eval

Both methods make use of eval. The typical mantra concerning this feature is that "eval is evil." However, that goes with say that using eval without knowing the dangers of eval is evil.

In this case, AFAIK, the data contained within the script tags is not subject to inject attack since the eval'ing script (the code shown) is executed as soon as that element is reached when parsing the HTML into the DOM. Scripts that may have been defined previously are unable to access the data contained within the counter's script tags as that node does not exist in the DOM tree at the point when they are executed.

It may be the case that a well timed setTimeout executed from a previously included script may be able to run at the time between the counter's script's inclusion and the time of the eval; however, this may or may not be the case, and if possible, may not be so consistently depending on CPU load, etc.

Moral of the story, if you're worried about it, include a non-eval'ing JSON parser and use that instead.

Justin Johnson