Tuesday, March 17, 2009

Prototype.js and for(..in..) loops

I had a problem a while ago where I was using a for(..in..) loop to go through a hash map (like an array but has strings for the index instead of numbers). Now you NEED a for(..in..) loop for these, because you don't always know what the indexes are going to be called, and you can't call them sequentially like a normal array. Problem was that I was getting back what looked like javascript functions instead of the values I expected, so I did what any programmer would do after finding no easy explanation - I just checked for that function keyword, the length of the string etc, and skipped over the values that were not in a format that would work. Since then I have encountered the problem again, but luckily it was on a site where the developer knew his stuff:

http://www.prototypejs.org/api/array

it seems that the prototype.js javascript library absolutely hates the for(..in..) loop. So for these site you have to return the array as an enumerable type and then use the each function. If you are writing code to go across multiple sites, you may want to use a try catch block to check the existence of each going forward.

You have now been warned

**Edit**

I stumbled upon this easy fix:

var object = new Object();
for(var key in object){
if(!(key in Object.prototype)){
// do some stuff SAFELY!
}
}

How To: Build a click macro insertion tool (part 2)

Please refer back to part 1 to go through setting up the bare bones.

In this part we will setup the script that can chang.values entered in and touch upon Regular Expressions or Regex. Regex is a fairly advanced topic and many experienced programmers struggle with it, while at first it may look like line noise it is in fac.very logical an.very powerful.

first off, let's make the button call a function. In the file from the previous tutorial I put in an onClick attribute on the button? after that put in a call to a function, let's say changeMe();

now let's make the function between the <script> blocks:

function changeMe(){alert( document.getElementById("myTag").value);}

This will make an alert box come up with the string inside the box. We can also set th.value:

function changeMe(){ document.getElementById("myTag").value = "HELLO WORLD";}

This will change th.value of the box to HELLO WORLD.

now for some regex fun. Let's do a useful example, Say we want this tool to secure any insecure creatives. What we need to do is change any http: to https: for any items brought in. To do this we first have to look for http:, the forward slashes you will see are what defines this as a regex

/http:/ - this is good, but what happens if we don't want to change the http in the links? we need only change the src="http:

/src="http:/ - This may be a little too strict, as there are many ways of putting this in. For instance the user may use double quotes or single quotes

/src=["']http:/ - the square brackets represent a character class - it means match any chacter inside. We will go deeper in to these in other how tos, but how about spaces around the equals sign?

/src\S*=\S*["']http:/ - the \S represents a whitespace and * represent 0 or more of the previous character. now I will make a couple of changes we will need later

/(src\S*=\S*['"]http):/gi - The brackets store the result of the match that we will need when replacing th.value, as we need to know whether to replace with a double or single quote, to make this pull everything up to where the s is though I have placed the brackets around most of the string. also I put g and i afterwards which are flags. The g means global, so for all instances - not just the first and i means ignore case.

now lets put this as the function:

function changeMe(){ document.getElementById("myTag").value = document.getElementById("myTag").value.replace(/(src\S*=\S*['"]http):/gi,"$1s:");}

the replace function takes the regex as the first argument and the string to replace it with as the second argument. The $1 part in the string is replaced byt what is matched in the first set of brackets.

now we are replacing the src=, but flash files also have data= o.value=. To fix this we could chain our regex replaces together like:

function changeMe(){ document.getElementById("myTag").value = document.getElementById("myTag").value.replace(/(src\S*=\S*['"]http):/gi,"$1s:").replace(/(data\S*=\S*['"]http):/gi,"$1s:").replace(/(value\S*=\S*['"]http):/gi,"$1s:");}

or we could use the regex OR, which is a pipe | and group them together. So it becomes (src|value|data). The function then becomes:

function changeMe(){ document.getElementById("myTag").value = document.getElementById("myTag").value.replace(/(src|value|data\S*=\S*['"]http):/gi,"$1s:");}

and that's it! what I would recommend is creating a new button and assigning this - and then we can play in different functions on different buttons

end result code:

<html>
<head>
<script>
function changeMe(){ document.getElementById("myTag").value = document.getElementById("myTag").value.replace(/((src|value|data)\S*=\S*['"]http):/gi,"$1s:");}
</script>
</head>
<body>
<form name="theForm">
<textarea rows=20 cols=20 name="myTag" id="myTag"></textarea><br>
<input type="button.value="go" onClick="changeMe();">
</form>
</body>
</html>

How To: improve adcode

now most major publishers have a similar approach to adcode as what I will outline. First I will go over the basics of a piece of adcode and what is needed. Then I will address the different types and finally list what can be improved in traditional adcode and how to do it.

Adcode Elements:

what we should look at first is the URL for the impression call of any piece of adcode. The elements that will make this up are:
1. Domain - this will call the server where the adserver is
2. Call - there will usually be a part that defines what kind of adcall it is, impression, click, and also what it should return
3. Site and location - variables that match to the targeting within your adserver
4. targeting - these are varibales that may or may not already be stored in your adserver. These fine tune the targeting
5. size/adtype - to define how big the ad is and what type of ad
6. other variables - different adserver will pas through different variables dependant on what is needed to use it's capabilities
7. cache buster - usually ord= or random=

Splitting the elements:

if you look at these elements you can see that some are used for all tags on a site (site, domain etc), some are used for the page (location, some targeting) and some are used for only that particular adunit (size, ord). So we code that is printed out several times for a site, or a page that only needs to be put in once. Why don't we group these variables and use javascript to write them out when needed

Advantages:

what we are going to do is make functions that will put in the code as needed when needed. What this allows is a change in one place to change all code for the page/site as opposed to changing all parts of the code. This makes code cleaner and easier to adjust. It also makes code easier to implement. If there is code already for the page, all we need to do is put in the code for an island to have an island appear - in fact one piece of island code could be put on any page

and it should pick up the site and page variables automatically. Also the code is non-adserver specific, so if you ever change adservers, you only need to change the file that hold the main methods - no changes to the site necessary

Method:

what we should do is create a separate .js file that holds methods to create the random cache buster and to automatically put in site variables. We then need a function that will set page variable dependant on what is passed in from the page. The final function we need will use the variables already set and variables passed in from the actual ad to write out the code.

an example of page code:

script src=" adcode.js ">/script>
script>
site = "site";
createSiteVars(site);
location = "location";
createPageVars(location);
/script>

then to call an ad:

script>
callAd(300,250,"javascript");
/script>

for extra bonus points, host the external script file with all functions somewhere you can access it so that you can hack away and make changes to site coding in a second if need be. Some examples of different implementations are whitepages.com.au and thevine.com.au