Adding click tracking / clicktags to iframes / HTML-ads in Adtech / Helios

After producing an HTML5 banner, living in an iframe, delivered through Adtech / Helios, we had a case where the clicks weren’t tracked by the advertising platform. That’s as expected, since the content hosting the iframe is unable to manipulate any content within the iframe (unless they’re on the same originating host, and we’re serving our content by ourselves to make it dynamic and without a huge setup cost (in time)).

Turns out Adtech / Helios has a few variables that it can replace when delivering the URL or the HTML of the iframe (similar to the function of a clickTAG for Flash content):

_ADCLICK_: Standard variable for click tracking
_ADCLICKESC_: URL is escaped by the ad server
_ADCLICKDEC_: Decoded target URL
_ADCLICKDECESC_: Decoded and escaped URL

We went with _ADCLICK_, which will be replaced by the URL to prefix any link in your own content with. That way the click will be routed through the tracking code at the ad server, and the counts should match what we’re actually seeing on the other side (through analytics and events).

Luckily the link to prefix does not contain any special characters that need to be escaped (they use ; as a separator) when used in as GET arguments in an URL, so you can add an argument to the existing URL:

http://www.example.com/?ad=1&clicktrack=_ADCLICK_
<iframe src="http://www.example.com/?ad=1&clicktrack=_ADCLICK_"></iframe>

You can then pick this up in your server side language and prefix all urls, or you can extract it in JavaScript and add it to any link available in dynamic content.

This also works in data- attributes for the iframe, allowing you to retrieve the click prefix through javascript from that parameter as well.

jQuery, Radio-buttons and attr(‘checked’)

To make this a bit more searcable on the magic intarwebs:

jQuery 1.6.x changed the behaviour of attr(‘checked’), as it is no longer used to manipulate the state of radio buttons (or other elements using the checked element). This is considered a property, not an attribute (the difference is subtle), so instead of:

    $("#element").attr('checked', 'checked'); // or
    $("#element").attr('checked', true);

The correct ™ way of doing this is:

    $("#element").prop('checked', true);

Complete Example of Tracking Start and End of Drag Operations with jQuery and Table Rows

After writing my previous post about “Keeping track of indexes while dragging in jQuery UI Sortable” I received a question about how this would work for sortable table rows. The code I included in the previous post should actually be enough to make everything work (.. as long as I understood the question correctly). I’ve created a minimal example as a complete implementation of the code from the previous post, and I’ve also included it as a live demo here.

This is based on jQuery 1.5.1 and jQuery UI 1.8.13. I’ve simply used the distribution versions of this example (you probably want to build your own UI bundle using the interface on the jQuery UI website).

Here’s a live demo that you can play with.

Inline javascript and WordPress could possibly be better friends.

The complete source for the minimal (but complete) example is included here:



    
        
        jQuery UI Example Page
        
        
        
        
    
    
        
Dragging from index
None
Hovering index
None
Keys Values
Key 1 Value 1
Key 2 Value 2
Key 3 Value 3
Key 4 Value 4
Key 5 Value 5
Key 6 Value 6

Keeping track of indexes while dragging in jQuery ui.sortable

While you’re handling a drag operation in the jQuery UI Sortable handler, there’s a few small issues that might almost drive you insane. These two solutions are based on information from various places on the net (such as a few discussions on Stack Overflow).

If you want to keep track of which location the item you’re dragging originated from, you can attach to the ‘start’ event in the Sortable configuration constructor. Use this event to attach the origin index as a data element:

start: function(event, ui) {
    ui.item.data('originIndex', ui.item.index());
},

If you want to find out what index the user is currently hovering above (to change the numbering of a list instantly), you can use the same method on the placeholder element (available as ui.placeholder, so to fetch the current index the user is hovering over, call ui.placeholder.index()). There is however a gotcha’ here, as the original element is still present in the list – just allow to float freely around (the dragging action). We handle this by fetching the origin index and subtracting one if we’re after the location we started at.

You can handle these events in the ‘change’ event handler:

change: function (event, ui) {
    var originIndex = ui.item.data('originIndex');
    var currentIndex = ui.placeholder.index();

    if (currentIndex > originIndex)
    {
        currentIndex -= 1;
    }

    // do magic
}

Unbreak My Hea.. Firefox Ctrl Click Please!

When we launched Gamer.no over a year ago, we had to come up with a wallpaper advertising solution in a rush (everything were a rush back then as we built and launched a site from scratch (after disagreements between the previous owner and Gamer) in just under four days (or 96 hours)). While this solution has worked .. good enough .. it has always had a few irky bugs that I’ve never really had the right inspiration to uncover the cause of. Usually I’ve spent an hour and decided that the time wasn’t worth it at the moment and then moved onto something else, but today! Today is a glorious day!

The bug has been fixed!

The wallpaper element is placed around the main content div, which sadly also makes the wallpaper element receive any click elements that the main content div receives. This leads to the wallpaper getting clicked and the wallpaper ad window opening regardless of where people click – which will get very, very annoying very quick. So to battle this issue the original solution was to call .stopPropagation() on the evt object in a click handler for the main content div. This solved the issue and everyone rejoiced! However, all was not perfect in paradise.

Some time later we discovered that the .stopPropagation() fix borked ctrl-click a link in Firefox. Other browsers handled it just fine, but Firefox were obviously not happy. Not happy at all. Mad and going on a killing spree it shot down the proposed fixes from both myself and other people who had a brief look at the code. It wasn’t a big issue as we only run the wallpaper code for small intervals of time and people didn’t complain (maybe we were some of the few who had the issue).

Today I decided to have a look at the issue again, and finally I realized that we had been way to focused on our call to .stopPropagation(). Everyone had been planning how we could get .stopPropagation to do what we wanted it to do – after all – the issue was that stopPropagation didn’t behave when we ctrl-clicked in Firefox. But wait.

If you instead think of the original problem; the window.open gets triggered when people click the inner element instead of the outer, there may be alternative solutions to using stopPropagation. And yes, THAT was quite a simple fix. Instead of trying to stop the event from bubling up through the cloud.. let’s just set a status variable that tells the code handling the wallpaper click that THIS CLICK IS NOT FOR YOU BAD HANDLER GO AWAY LET OTHER GROWNUPS HANDLE THIS. So that I did.

$(document).ready(function () {
    innerClick = false;
    $('#wallpaper').click(function() {
        if (innerClick)
        {
            innerClick = false;
            return true;
        }
        
        window.open("..");
    });
    $('#content').click(function(evt) {
        innerClick = true;
    });
});

As soon as I actually spent some time on what we were trying to solve instead of what seemed like the cause of the issue .. everything went better than expected.

jQuery, .getJSON and the Same-Origin Policy

When creating a simple mash-up with data from external sources, you usually want to read the data in a suitable format – such as JSON. The tool for the job tends to be javascript, running in your favourite browser. The only problem is that requests made with XHR (XMLHttpRequest) has to follow the same origin policy, meaning that the request cannot be made for a resource living on another host than the host serving the original request.

To get around this clients usually use JSONP – or a simple modification of the usual JSON output. The data is still JSON, but the output also includes a simple callback at the end of the request, triggering a javascript in the local browser. This way the creator of the data actually tells the browser (in so many hacky ways) that it’s OK, I’ve actually thought this through. Help yourself.

In jQuery you can trigger the usual handling of events by using “?” as the name of your callback function. jQuery will handle this transparently and then trigger the function you provided to .getJSON in the first place.

Example

url = "http://feeds.delicious.com/v2/json/recent?callback=?";

$.getJSON(url, function(data) { alert(data); });

There’s an article up at IBM’s developerWorks giving quite a few more examples and information about the issue.

A couple of issues with SWFUpload 2.5.0b1

The first beta of SWFUpload 2.5.0 was released during christmas, and just a few quick notes for those who are going to attempt an upgrade:

button_cursor: SWFUpload.CURSOR.HAND,

.. seems broken. This will probably be fixed soon, but currently I’ve been unable to get the proper mouse cursor for a button.

If you previously relied on any custom settings being available in the settings object (by providing them when initializing the component), SWFUpload 2.5.0 does not include them in the this.settings object any longer.

If you want to include any custom settings, they’ll now have to be included in a setting for that purpose (together with the other options in the settings object):

swfu = new SWFUpload({
    [settings settings]
    custom_settings : {
        redirect : true,
        redirect_delay : 500
    },
    [more settings]
});

These values will then be availble through this.settings.custom_settings in your callback functions, such as this.settings.custom_settings.redirect etc.

Both issues has been reported on the v2.5.0b1 announcement.

Avoiding Resetting the Scroll Position in a Textarea When Inserting Content

Now, that’s quite a headline. And this post will explain just the simple concept posted in the headline. How to avoid (at least) firefox from scrolling to the top when you insert content into a textarea.

It’s simple. Very simple. And it was shown to be so very simple for someone who didn’t remember scrollTop by this thread.

In jQuery (which we use with the caret plugin):

currentScrollPosition = $("#textareaId").scrollTop();
/* do stuff */
$("#textareaId").scrollTop(currentScrollPosition);

Yep. So simple that it actually hurts a bit.

Adding SVN Revision to a Configuration File

After a while you realize that the best way to serve almost-never-changing content is to give the content an expire date way ahead in the future. The allows your server and your network pipes to do more sensible stuff than delivering the same old versions of files again and again and again and again.

A problem does however surface when you want to update the files and make the visiting user request the new version instead of the old. The trick here is to change the URL for the resource, so that the browser requests the new file. You can do this by appending a version number to the file and either rewriting it behind the scenes to the original file, or by appending a timestamp (or some other item) to the URL as a GET value. The web server ignores this for regular files, but as it identifies a new unique resource, the web browser has to request it again and use the new and improved ™ file.

Using the timestamp of the file is a bit cumbersome and requires you to hit the disk one additional time each time you’re going to show an URL to one of the almost-static resources, but luckily we already have an identifier describing which version the file is in: the SVN revision number (.. if you use subversion, that is). You could use the SVN revision for each file by itself, but we usually decide that the global version number for SVN is good enough. This means that each time you update the live code base through svn up or something like that (remember to block .svn directories and their files if you run your production directory from a SVN branch. This can be discussed over and over, but I’m growing more and more fond of actually doing just that..). To avoid having to call svnversion each time, it’s useful to be able to insert the current revision number into the configuration file for the application (or a header file / bootstrap file).

Here’s an example of how you can insert the current SVN revision into a config file for a PHP application.

  1. Create a backup of the current configuration file.
  2. Update the current revision through svn up.
  3. Retrieve the current revision number from svnversion.
  4. Insert the revision number using sed into a temporary copy of the configuration file.
  5. Move the new configuration file into place as the current configuration file.
  6. Party like it’s 1999!

This assumes that you use an array named $config in your configuration file. I suggest that you name it something else, but for simplicity I’m going with that here. First, create a $config[‘svn’] entry in your config file. If you have some other naming scheme, you’re going to have to change the relevant parts below.

#!/bin/bash
cp ./config/config.php ./config/config.backup.php
svn up
VERSION=`svnversion .`
echo $VERSION
sed "s/config\['svn'\] = '[0-9M]*';/config\['svn'\] = '$VERSION';/" < ./config/config.php > ./config/config.fixed.php
mv ./config/config.fixed.php ./config/config.php

Save this into a file named upgrade.sh, make it executable by doing chmod u+x upgrade.sh and run it by typing ./upgrade.sh.

And this is where you put your hands above your head and wave them about. When you’re done with that, you can refer to your current SVN revision using $config[‘svn’] in your PHP application (preferrably in your template or where you build the URLs to your static resources). Simply append ?v=$config[‘svn’] to your current filenames. When you have a new version available, run ./upgrade.sh (or whatever name you gave the script) again and let your users enjoy the new experience.

An Update to jQDynamicFontSize

When we released jQDynamicFontSize a couple of weeks ago, we hoped that others would find the plugin useful and keep it around as one of the many tools in your toolbox. We also had a small hope that people would find it useful to extend and maybe submit a patch or two back to us.

And lo’ and behold, during the weekend the first patch arrived in my mailbox. Written by Vegard Andreas Larsen, we now also support scaling against the width of a container. I didn’t even have an idea around this, and suddenly we have working code. The power of open source!

This adds two new options when initializing jqDFS:

  • limitWidth: Uses the width of the element to determine the size instead of the height. Defaults to false.
  • allowUpscaling: Allows the element to grow instead of shrink to fit the provided area. Only works when limitWidth is active currently. Defaults to false.

The original scale method should probably be rewritten to also use allowUpscaling, so if anyone feels slightly hackish tonight, just send the patch my way!