Archive for the 'AJAX' Category

My online footprint lately

Wednesday, July 23rd, 2008

This is a sort of a catch-up post for listing what I've been up to lately.

  • YUI Blog just published my first article, I'm so proud. It's about loading JavaScript in non-blocking fashion, because JavaScripts, they, you know, like, block downloads. Luckily, there's an easy fix - DOM includes, which I've previously discussed, discussed and discussed.
  • SitePoint published an update to my older article that introduces AJAX, ok, Ajax, by creating a command-line-like interface with PHP on the server side. The updated article features improved code, jQuery example, YUI example, JSON discussion and example. Check it out, bookmark and recommend to your friends that keep asking you "What's this AJAX (they are new, don't know it's now spelled "Ajax") thing? Do you know of a good article?"
  • YDN (developer.yahoo.com) published a video presentation of me and my lovely teammate Nicole Sullivan where we talk about some new and cool front-end performance techniques. So if you wandered how I look and are eager to hear my fabulous Balkan peninsula accent, give it a shot. The talk is called "After YSlow 'A'" and is targeted at those of you who have reached performance nirvana, but are still hungry for more. We talk about preloading components, post-loading, javascript, images, using flush() in PHP to send first byte early on and other fun stuff.
  • Last, not least, I decided to try and find some time to update my JavaScript patterns site. Unfortunately I got sidetracked (yep, I'm easily distracted by shiny objects) and played with a not-so-javascript pattern. The post I published (includes a pretty lame screencast! and) demonstrates how you can use animated background position to indicate loading progress.

Whew, c'est tout pout ce moment, expect a lot more now that the JavaScript book is out of the way. Ah, yep, if you feel like it, join me on Facebook, I created a JS book page.

 

CSS Sprites generation tool

Wednesday, June 27th, 2007

Here's my last weekend's project - a web-based tool to generate images for CSS sprites: http://www.csssprites.com. Cool domain name, eh? I couldn't believe it was not taken.

CSS Spr...what?

This is a simple technique used for page load performance purposes. Since HTTP requests are the most expensive thing you can do in regards to front-end performance, you strive for making as little requests as possible. So instead of having the browser download 4 rounded corner images for example, you create one image that has all four. Then you use CSS' background-position to only show the part of the image you want. More on the subject in this ALA article

How does the tool work

You upload as many images as you want and the tool generates a mosaic of all images, gives you the result as PNG and gives you the coordinates you need to use in the background-position declaration. The tool also gives you an html page as an example, so you can save both the PNG and the html page for reference.

Image size

If you properly optimize the big image, you might actually have smaller size than all the individual images combined. In my tool, the PNG image generated is not optimized at all, I leave this to you to use PNGOUT or any other tool you know. Also you can convert the PNG into GIF if that's better for your purposes.

Implementation - PHP

The PHP code is fairly simple. The actual spriting (is that a word?) class takes a list of images and calls getimagesize() on each one to get the dimensions. The image with the biggest height is used as distance between images. The rest is just composing the imagemagick command that will to the work. Here's the important method:

<?php
function combine() {
    if ($this->distance === false) {
        $distance = $this->_biggest;
    } else {
        $distance = (int)$this->distance;
    }

    if ($this->output_dir === false) {
        $output_dir = $this->_dir;
    } else {
        $output_dir = $this->output_dir;
    }

    $half = ceil($distance / 2);

    $coord = array();
    $y = 0;

    foreach ($this->images as $i=>$data) {
        $this->images[$i]['x'] = $half;
        $this->images[$i]['y'] = $half + $y;
        $coord[] = '-page +0+' . $y . ' ' . $i;
        $y += $data[1] + $distance;
    }

    $cmd = 'convert ' . implode(' ', $coord)
         . ' -background none -mosaic -bordercolor none -border '
         . $half . 'x' . $half
         . ' ' . $output_dir . '/result.' . $this->output_format;
    system($cmd, $ret);

    return $ret === 0;

}
?>

Implementation - JS

In the spirit of web2 I couldn't afford a complete page reload :lol: although it would've been much simpler. I just had to get fancy. YUI to the rescue. On page load I set up the form for async request, using YAHOO.util.Connection. In case of file uploads YUI generates an iframe behind the scenes and uploads to the iframe. Then it takes whatever is in the body on the iframe and gives it to you instead of the XMLHttpRequest's responseText property.

So the files are uploaded to upload.php which calls the class that has the method mentioned above then loops through the $images property of the said class and writes the example html file as well as prints out a JSON string with the same image information.

YUI's Connection calls my callback function and I get the invaluable responseText. Parsing the JSON with the json.js, I get a JS object. Looping through it and DOM-generating a table of results is the semi-last step. The last is (we're fancy, remember?) to yellow-fade the background color of the result, using YAHOO.util.Animation.

BTW, I got fancy once again and combined and minified json.js with my JS file, so that there is one less request and a side effect impossible to read. The unminified version of the JS that does all the work is here for reference.

Comments

I hope this tool cane be useful for quickly generating those sprites, if only for prototyping purposes. Any comments, requests, bug reports are all very welcome.

And how do you like the version of the tool? Anyone n00b can do "beta", it takes a true h@x0r (or something) to do a better job :D

Ah, yeah, and the page badly needs a stylesheet, do you want to help?

 

AJAX-MCV in Russian

Monday, January 29th, 2007

Boris of http://www.ajaxplanet.ru/ has published a translation of my article on the little AJAX/MVC framework I came up with, this is trully flattering, thanks a lot!

If you speak Russian check the post here.

The translation is by Gennady Potapov, sposibo Gennady!

 

JSON renderer for Text_Highlight

Friday, October 27th, 2006

Text_Highlighter is one of my favourite PEAR packages, seems like I'm addicted to highlighting source code. After adding BB code and simple HTML renderers and an ABAP code syntax definition, today I played with adding a JSON renderer. Useful in case you want to get highlighted source code in your new shiny AJAX app.

Array renderer

After I did the JSON renderer, I said, OK, what if I want to tweak the JSON output just a bit (or the output from any renderer for that matter)? Add more options? Nah, I had a better idea, I scrapped the whole thing and did an Array renderer first. If you have the array output from the renderer, it's trivial to format it as JSON, or XML, or HTML, or anything. I believe even the exisitng Text_Highlighter renderers should be rewritten, to extend an Array renderer. Anyway, back to JSON.

Demo

To see the JSON renderer in action, you can go to my hiliteme.com site and check the JSON tab.

Source

The source code is available here - JSON.phps which extends Array.phps. To test, you need to add the two renderers to your PEAR repository under Text/Highlighter/Renderer

Example

So let's say you need to highlight the PHP code

<?php
    echo "Hello Highlighted World!";
?>

You create an instance of Text_Highlighter and Text_Highlighter_Renderer_JSON and call the highlight() method, assuming that the code you need highlighted is in $source

<?php
// dependencies
require_once 'Text/Highlighter.php';
require_once 'Text/Highlighter/Renderer/JSON.php';

// instance
$json_options = array();
$json_options['tabsize'] = 4;
$json_options['enumerated'] = true;
$renderer =& new Text_Highlighter_Renderer_JSON($json_options);
$highlighter =& Text_Highlighter::factory($_POST['language']);
$highlighter->setRenderer($renderer);

// do the highlighting
$json_result = $highlighter->highlight($source);
?>

Now $json_result will look like:

[["inlinetags","&lt;?php"],["code"," \\n    "],["reserved","echo"],["code"," "],["quotes","&quot;"],["string","Hello Highlighted World!"],["quotes","&quot;"],["code","; \\n"],["inlinetags","?&gt;"]]

As you see the JSON output is an array, one element per highlighted keyword, and in this array there is a sub array - class/keyword. If you want to display this in your page (let's say you got it from an AJAX call), you can do a loop through the array and surround the keywords with span tags of the selected style:

// say your ajax call returned var src 
// var src = xmlhttp.responseText;
var data = eval(src); 

var res = '';
for (var i in data) {
    res += '<span class="hl-' + data[i][0] + '">';
    res += data[i][1];
    res += '</span>';
}

var el = document.getElementById('some-div').
el.innerHTML = '<pre>' + res + '</pre>';

Here I used innerHTML, you can also use DOM, but in this case you need a special case for the "\n" so that you can create a br element to address IE's habit of ignoring line feeds in a DOM-generated pre tag.

BTW, if you don't set the enumerated option to true, you'll get objects inside the main array, check hiliteme.com's JSON tab for an idea of how this would look like.

 

AJAX MVC (so to speak)

Tuesday, September 19th, 2006

This is sort of a framework thing to create AJAX applications, based on the MVC design pattern. Yep, I have a lot of buzzwords here, I admit, but this shouldn't be taken too seriously. I was doing a bunch of small projects lately and I found myself using something like this little framework, without even thinking about it. Then I thought about it and I found that the scripts and the organization of them may resamble MVC a bit. So how does MVC fit when you mix things like thin and fatter client, HTML, JavaScript, XMLHttpRequest, PHP and CSS?

Usual AJAX app flow

What usually happens in an AJAX application is:

  1. you have an HTML page, styled with CSS
  2. you click on something
  3. JS sends request to the server (to a PHP script)
  4. JS updates the original HTML page

Mapping to the MVC pattern

OK, so what part of this process can be associated with a View, or a Model or a Controller? The Model is easy, it's the business logic, writing to a database and so on. This is the PHP script. The View? Obviously this is the HTML page and the CSS. But I'd like to think also about the JS that updates the page as part of the View. I mean it makes sense, it's updating the presentation part. Sometimes you even use innerHTML in the JS, but even if you use DOM, it becomes part of the HTML anyway. How about the Controller? Well, we have two controllers here. One that is on the server side, a PHP script that receives requests and "asks" the Model for the response. The other controller is on the client side, this is the JavaScript that decides what happens on a click of a button and sends an appropriate AJAX request to the PHP controller. Therefore I would consider any behavioural JS as part of the Controller, including attaching events as well as sending HTTP requests.

Here's an illustration:
AJAX MVC

In action (example)

I went ahead and implemented a very simple application to prove the concept. It's just a blank styled HTML page with a button. The HTML page includes two JavaScripts responsible for behaviours (Controller) and page updates (View). The page also includes a few unrelated helper javascripts, in my case I'm using the YUI library. The JS Controller attaches an event to the button. Then when you click the button, the JS Controller sends a request to the PHP controller. The PHP controller (just a simple switch) figures out what was requested and calls the appropriate object of the business model. In my simplistic case, the abovementioned "model object" is just a simple function, but this can be easily built upon. The Model returns (JSON-encoded) response, in this case it's a list of installed PHP extensions. Now the response is received by the View JS and it updates the page. After that the View calls another function from the JS controller that attaches new events to the new content. (Yep, a little glitch here, maybe it would have been better if the Model's response is handled by the JS controller which in turn calls the JS view updater, but anyway this is easy to fix)

Directory layout

Here's the directory structure:
AJAX MVC dir

One might argue that it's better if you don't mix .js, .css and .php files in the same directory but the whole idea is open to interpretations anyway, it's just an illustration of the idea.

The code for the example

We get to the fun part, the actual implementation. So we start with a simple .html page, the initial part of the view.

This is index.html

<?xml version="1.1" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>Welcome</title>
  <link rel="stylesheet" href="../view/styles.css" type="text/css" media="all" title="Default styles" />
  <script language="javascript" type="text/javascript" src="../_extras/yui/build/yahoo/yahoo-min.js"></script>
  <script language="javascript" type="text/javascript" src="../_extras/yui/build/event/event-min.js"></script>
  <script language="javascript" type="text/javascript" src="../_extras/yui/build/connection/connection-min.js"></script>
  <script language="javascript" type="text/javascript" src="../view/updates.js"></script>
  <script language="javascript" type="text/javascript" src="../controller/behaviours.js"></script>
</head>
<body>

  Welcome to my app!
  <br />
  <form action="" method="post">
    <input type="button" name="b" id="thebutton" value="I'm a button, click me!" />
  </form>
  <div id="content">&nbsp;</div>

</body>
</html>

As you can see, nothing special, simply including the CSS styles, the YUI "extras" and two other javascripts - one part of the View and one that is part of the Controller.

The Controller JS is responsible for attaching an event listener to the button.

This is an excerpt from the behaviours.js

// the behaviour class
var behaviours = {

    phpcontroller: "../controller/switch.php?request=",

    // more behaviour.methods....
}

// initial page load, attach onload event(s)
YAHOO.util.Event.addListener(
    'thebutton', 'click', behaviours.theButtonClick);

Now when the user clicks the button, the method behaviours.theButtonClick() is executed. It fires a request to the PHP controller switch and says that the request type is "loadSomething":

theButtonClick: function(e) {
  alert('Ouch! \n\nOK, I\'ll make a request for ya, buddy!');
  YAHOO.util.Connect.asyncRequest (
      'GET',
      behaviours.phpcontroller + 'loadSomething',
      {success: updates.writeContent}
  );
},

The PHP controller (controller/switch.php) receives the request, does a simple switch to validate the request type and then calls the appropriate (in my case just a simple) function from the business model. Here's the full switch.php code:

<?php
// is this a request?
if (empty($_GET['request'])) {
  die();
}
// get the business logic
include_once '../model/business.php';

// figure out the request
// and call the business logic object
switch ($_GET['request'])
{
  case 'loadSomething':
    echo loadSomething();
    break;
  case 'loadSomeMore': // not used, example
    echo loadSomeMore();
    break;
}
?>

The function loadSomething() from the PHP model gets a list of installed PHP extensions, encodes them into JSON and sends them back. This is a full listing of the ../model/business.php

<?php
function loadSomething() {
  $extensions = get_loaded_extensions();
  return '["'. implode('","', $extensions) . '"]';
}
?>

If you go back and look at the AJAX request, you'll see that on success, I call the updates.writeContent() method. The ../view/updates.js script contains stuff that updates the HTML of the original page, so its place is in the View part of the app. writeContent simply creates an HTML table with the results (the list of PHP extensions). Then I wanted to attach event listeners to this table just to change color, but it can be more than that. Attaching events is a job for the JS Controller, therefore a method of its class is called. Here's a full listing of updates.js:

var updates = {

  writeContent: function (xmlhttp) {
    if (!xmlhttp.responseText) {
      alert("I got nothing from the server");
    }
    var data = eval(xmlhttp.responseText);
    var write_to = document.getElementById('content');
    write_to.innerHTML = ''; // yeah, I know

    var html2dom_root = write_to;
    var table = document.createElement("table");
    var table_1_tbody = document.createElement("tbody");
    for (var i in data) {
      table_1_tbody_2_tr = document.createElement("tr");
      table_1_tbody_2_tr_1_td = document.createElement("td");
      num = 1 + parseInt(i);
      table_1_tbody_2_tr_1_td_1_text = document.createTextNode(num);
      table_1_tbody_2_tr_1_td.appendChild(table_1_tbody_2_tr_1_td_1_text);
      table_1_tbody_2_tr.appendChild(table_1_tbody_2_tr_1_td);
      table_1_tbody_2_tr_2_td = document.createElement("td");
      table_1_tbody_2_tr_2_td_1_text = document.createTextNode(data[i]);
      table_1_tbody_2_tr_2_td.appendChild(table_1_tbody_2_tr_2_td_1_text);
      table_1_tbody_2_tr.appendChild(table_1_tbody_2_tr_2_td);
      table_1_tbody.appendChild(table_1_tbody_2_tr);
    }
    table.appendChild(table_1_tbody);
    html2dom_root.appendChild(table);

    behaviours.updateTableBehaviour();
  }
}

(BTW, for the DOM part I'm used the help from my little tool html2dom to make my life a bit easier)

And finally here's the rest of the JS controller (behaviours.js), the method behaviours.updateTableBehaviour() that adds an event listener to the new table and the trClick() that handles clicks on this table. On click, it justs changes the color of the underlying row.

  trClick: function (e) {
    var target = (e.srcElement) ?
      e.srcElement.parentNode : e.target.parentNode;
    if (target.tagName == 'TR') {
      if (target.className == 'tr-on') {
        target.className = '';
      } else {
        target.className = 'tr-on';
      }
    }
  },

  updateTableBehaviour: function () {
    var el = document.getElementById('content').firstChild;
    YAHOO.util.Event.addListener(
      el, 'click', behaviours.trClick);
  }

Demo and downloads

  • Demo - the live example
  • Zipped demo - all the source code for the example
  • Template - the source code for the example but with the example part commented, so you can use it as a template for your next AJAX project. The only thing you need to do is to drop the YUI in the _extras/yui folder.

Thank you for reading, any comments welcome!

 

HTML2DOM

Thursday, September 14th, 2006

Here's this HTML-2-DOM service - http://www.html2dom.com What it does is pretty simple - you paste some HTML code and the output is JS script code that uses DOM functions to produce the same result. Could be useful when you're working on an AJAX-style app that generates new content using JavaScript.

I build this simple script, inspired by this great book I was reading - "Build Your Own AJAX Web Applications". In the book, the author sometimes starts with writing up what is the HTML code for the result you want to achieve, and then goes ahead with giving the DOM code. Because, you know, DOM code can be quite verbose and sometimes a bit hard to follow. So I thought, why not write up a simple tool to automate this HTML to DOM transition.

The code is not complicated at all, it just takes the HTML, treats it as an XML document, then loops through all the elements of the XML doc and all the attributes for each element. The script is here, hopefully reusable and you can grab it for your own projects if you wish. You can check the source of html2dom.com's index page for an example how to use the html-2-dom class.

Some limitations of the script (that I know of) are result of the fact that I'm treating the HTML as XML document. So you might get some errors if the HTML you paste is not well-formed, with all closed tags and so on. Also you cannot use &nbsp; and other entities, because XML doesn't know about them. What XML knows is only the pre-defined 5. And last, out of the different node types, my script understands only three - element, attribute and comment. I think it's enough for the practical purposes I was aiming at, even the comment type is a bit of a stretch.

So enjoy and as always, any feedback is welcome!

 

Fly Yahoo UI

Tuesday, March 28th, 2006

Here goes the rhyme:
Make your content management application fly
with the Yahoo library of JavaScript UI...

Making fancy UI stuff has never been easier. Google released their JavaScript XSLT library, Prototype is everywhere, others too... now Yahoo! released their UI library. I took a look at Y! stuff, let me show you what I did.

» Before you continue, feel free to check the demo at any time

CMS

OK, let the first one who has never coded some sort of Content Management System throw a stone. Yep, that's what I thought. Writing a CMS is like the new Hello World ;)

A very simplistic CMS would have a bunch of data records and options to add new records, to modify existing entries or to delete them. Let's see how to do the deletion fly, web 2.0. style.

The table

The records are stored in a very, very basic table that has its markup to the bare minimum. The table has an ID "records" and every link also has an id like "delete-1", "delete-2", etc, where the numbers are the record IDs from the database table. The beauty of this is that the links go to delete.php, a server side script that will delete the requested record and return something. So this will work even for JS-disabled browsers. For those that are enabled though, we'll make the links not navigate to delete.php, but send a small AJAX request to that same server-side script.

Here's the table markup, as you can see, very minimalist.

<table id="records" align="center">
  <caption>Table with records in it</caption>
  <tbody>
    <tr>
      <th>Last Name</th>
      <th>First Name</th>
      <th>&nbsp;</th>
    </tr>
    <tr>
      <td>Man</td>
      <td>Super</td>
      <td><a href="delete.php?id=1" class="delete" id="delete-1">delete</a></td>
    </tr>
    <tr>
      <td>Woman</td>
      <td>Cat</td>
      <td><a href="delete.php?id=2" class="delete" id="delete-2">delete</a></td>

    </tr>
    <tr>
      <td>Man</td>
      <td>Invisible, The</td>
      <td><a href="delete.php?id=3" class="delete" id="delete-3">delete</a></td>
    </tr>
  </tbody>
</table>

Attach an event

To make the links call a JavaScript function, we'll have to attach an event to them. For this, let's use Y!s event library (event.js). Here's all that's needed:

// add an onclick listener to the records table
YAHOO.util.Event.addListener('records','click',clickHandler);

Very simple, right? Now we've attached an event to the whole table. That's far more convenient than attaching an event to each and every link. With the line above we stated our desire that whenever there is a click somewhere inside the table, the function clickHandler() is executed. Let's see what's in there.

clickHandler()

function clickHandler(e) {
    // make sure the default event (vistiting the link) is not executed
    YAHOO.util.Event.preventDefault(e);
    // which element was clicked (target is in W3C, srcElement is in IE)
    var target = (e.srcElement) ? e.srcElement : e.target;
    // if the target element has class named "delete", that's our dude
    if (target.className == 'delete') {
         if (confirm('Sure you wanna delete?')) { // be polite, ask first
            // figure out which record to delete
            var id_to_delete = target.id.replace('delete-','');
             // the ajax stuff
            YAHOO.util.Connect.initHeader('my_ajax','oh yes it is');
            YAHOO.util.Connect.asyncRequest (
                'GET',
                'delete.php?id=' + id_to_delete,
                {success: removeRow,
                 failure: function (xhr) {
                                alert('Error :( try later...');
                           },
                 cell_id: target.id
                }
            );
        }
    }
}

As you see, I've put quite a bit of comments to illustrate what's going on at each line. Maybe the AJAX part will still need some more details though.

First, the header setting. Using YAHOO.util.Connect.initHeader we'll send an additional HTTP header, called my_ajax with some funny value. The purpose of this exercise is to tell our server-size delete.php script that this is an AJAX request and it will return a different response once it does its thing.

The actual request is made using YAHOO.util.Connect.asyncRequest. We pass the request method (GET), the URL (delete.php?id=12345) and then we pass an object to tell that if the request was successful, the function removeRow() should be called. On failure, an anonymous function is executed to simply alert that something's wrong.

The success and failure methods form the so-called callback object. You need a callback to instruct the AJAX call what to execute next. In the callback object you can also pass anything you like, like the property cell_id for example.

removeRow()

This function will be executed once the AJAX call completes successfully. In the function we'll:

  1. Check if the server-side returned "ok" response.
  2. Paint the row to be removed red
  3. Animate the row until it fades
  4. Remove the row completely

You may think that part 1 of this plan is funny? Laugh all you want, but if you think about it, it may start making sense ;) I mean you're right, it's AJAX, it should be Asynchronous JAvascript and XML. But we don't need no stinkin' XML for such a minor thing. A simple, friendly 'ok' is all it takes. No <root>s, no getElementsByTagName().item() end so on.

One hiccup in the plan is that the Yahoo UI doesn't yet support color animation. But we can use opacity animation. Good, great. Only that animating the opacity of a table row doesn't work in IE6. Shoot! Solution? Loop though the cells of the row and animate them. It will work.

Once all is animated and done, the last thing is to remove the row. It's easy, but we want to make sure it's done only after the animation is completed. Hence the "subscription" the Y! library provides.

Here's the function in its whole, see the comments.

function removeRow (xhr)
{
    if (xhr.responseText != 'ok') {
      alert('Error, try later...');
      return;
    }
    // now let's remove the row that contained the record
    var row = document.getElementById(this.cell_id).parentNode.parentNode;
    row.style.backgroundColor = '#ff0000';  // make it red

    // will make the removal animated
    var attributes = {opacity:{from:1, to:0}}; // will animate until opacity is 0

    // loop through each cell and animate it
    // animating the opacity of a row (not all cells) is preferable,
    // but it's not happening on IE
    for(var i=0, thecells = row.cells; i < thecells.length; i++) {
        var anim = new YAHOO.util.Anim(
            thecells[i], // animate what
            attributes,  // animate how
            1,           // for how long
            YAHOO.util.Easing.easeOut // and a dynamics touch
        );
         if (i == thecells.length - 1) {
            anim.onComplete.subscribe( // execute on completion
              function(){
                row.parentNode.removeChild(row); // remove the row
              }
            );
        }
        anim.animate();
    }
}

The server-side check

As mentioned earlier, delete.php will delete the row regardless of how it's called - directly from the browser or through the AJAX call. The difference is that the response will be different. How does delete.php know how to respond? Looking at the extra header we sent, of course! Here goes:

<?php
// First off, do the actual record deletion
// check for permissions, etc

// When it comes to reporting,
// respond differently if called with AJAX request or normally
if (!empty($_SERVER['HTTP_MY_AJAX'])) {
    // this is an AJAX request
    // the response can be XML, JSON, whatever
    // for my purposes, a simple status reply is enough
    echo 'ok';
} else { // a normal browser request
    // do something, like header('Location: ...') for example
}
?>

Conclusion

So that's it, hope you enjoyed the trip. Once again, the demo is here, the Yahoo UI is here and ... have fun with the Y! library! Though despite the excitement of the new toy, please do not forget to sleep daily, it's important (I hear) ;)

 

toAjax() in about 6 hours 49 mins

Saturday, February 25th, 2006

A funny thing - today I found out that there is the Town of Ajax, a city near Toronto, in my neighbouring Canadian province, Ontario (I'm in Quebec). It would take me about 6 hours 49 mins to get there. Anywone else want to move and join me in creating the newset coolest Web 2.0. company, based in Ajax, ON ;)

AJAX - Asynchronous JavaScript And XML (W) - is the cool kid on the block for us, webdevs, I believe since April 1st, 2004 (when Gmail was launched, although we didn't call it AJAX back then). But what else does "ajax" mean?

  • My first association when I read about it was with Ajax, one of the heroes in Homer's Iliad (W)
  • Not doing too much cleaning around the house, or maybe a fan of Mr.Clean (known as Mr.Proper back in my home Bulgaria, in Europe), I didn't know that there is Ajax, the cleaning thing.
  • I swear I knew, but have forgotten, about Ajax, the football team, since I was ball-kicking, goal-keeping kid at one point.

It turns out there's more to AJAX than this, for more, there's always the Wikipedia.

But now, 'scuse me while I pack my things and move to Ajax, ON.

 

AJAX banner rotation

Monday, February 13th, 2006

So here's the case: rotate ads on a website, even when the page is not reloaded. If the chances are that the visitor will spend more time on a page, it makes sense to opt-in for displaying more than one ad at one page load. I've done this in the past using iframes, but hey, it's 21st century (the last time I checked) and we have AJAX! ;)

I also wanted to have the flexibility to display any ad type, which means I should be able to rotate pieces of HTML, rather than just images. Using HTML chunks, the ad can be an image, or formatted text, or swf, etc.

Demo

If you're curious to see the demo, go straight ahead (nothing impressive, I must admit, just rotating stuff ;) ).

Getting busy

The "architecture" is fairly trivial - one HTML page (demo.html) and one JavaScript (ajax-banner.js) that makes XMLHTTP requests to a server-side script (ajax-banner.php). The server side (that has all the logic to figure out the next advertisement to show) returns XML response which is received by the caller JS and then displayed in a div on the HTML page.

<div id="ajax-banner"></div>

The server-side script

For the purposes of the example, the ad logic is simple - an array of HTML chunks, we pick a random one and return it as part of the XML response. In addition to the HTML chunk, as part of the XML response, the server-side script also produces an "instruction" as to how long should the ad be displayed.

Here's how the script looks like:

<?php
// an array of banners
$banners = array (
    '<em>ban</em>ner 1',
    'banner <strong>2.0.</strong>',
    '<h1>big banner</h1>',
    'Inline JS won\'t run :( <script>alert("boom!")</script>',
    'External JS won\'t run :(( <script src="test.js"></script>',
    '<img src="phpied.gif" />'

);
// pick a random one
$html = $banners[array_rand($banners)];

// send XML headers
header('Content-type: text/xml');
echo '<?xml version="1.0" ?>';

// print the XML response
?>
<banner>
    <content><?php echo htmlentities($html); ?></content>
    <reload>5000</reload>
</banner>

The javascript

The javascript consists of three functions. The main "dispatcher" is nextAd() which loads the next ad in the div. nextAd() calls the makeHttpRequest() function to send a request to the server-side script and then passes the response to loadBanner() which actually updates the banner div.

makeHttpRequest()

I've been using this simple function I came up with for a few projects (like theInvisibleAd.com) No AJAX libraries or toolkits are necessary as the task is pretty straightforward.

This function makes an HTTP request and passes the response to another function, specified on-the-fly. The function is the bare basics of the AJAX thing and if you're interested in the details you can check my article on SitePoint where I've used it to create a simple web console application.

nextAd()

This function makes the request and passes the response to loadBanner(). The HTTP request uses the current time in milliseconds to try to prevent the client browser from using a cached copy from the previous request.

function nextAd()
{
    var now = new Date();
    var url = 'ajax-banner.php?ts=' + now.getTime();
    makeHttpRequest(url, 'loadBanner', true);
}

loadBanner()

loadBanner() accepts the XML response generated by the server-side script. The XML has two tags - content (the HTML to be displayed) and reload (the allocated time for this ad to be displayed). The banner div is updated with the new HTML content using innerHTML the simplest, yet questionable by some purists, including myself, way of updating an already loaded page with JS.

Once the ad is updated, old timeout is cleared (if any) and a new timeout is set, the time in milliseconds after which we'll call nextAd() again to make the next HTTP request.

function loadBanner(xml)
{
    var html_content = xml.getElementsByTagName('content').item(0).firstChild.nodeValue;
    var reload_after = xml.getElementsByTagName('reload').item(0).firstChild.nodeValue;
    document.getElementById('ajax-banner').innerHTML = html_content;

    try {
        clearTimeout(to);
    } catch (e) {}

    to = setTimeout("nextAd()", parseInt(reload_after));
}

Conclusion

There's one drawback to this method though - any javascripts (inline or external) in the ad's body won't get executed. I have a remedy for this - including JavaScripts on the fly, outlined in this posting, but in this case I need to know something about the HTML returned by the server-side script, which can be passed as another tag in the XML, saying something like <is-this-js> -> you bettcha! In this case the solution will become less of a one-size-fits-all, but still a viable option.

Overall, if you don't plan to use JS in your ads, the solution outlined in this post is very simple and seems like ideal for replacing iframe-based banner rotations using sexier AJAX.

 

XAJAX intro and more from Marco

Sunday, November 20th, 2005

Marco, this great guy and talented web-dev from Netherlands (spelled ?????»?°???????? in Bulgarian, as in Holland), has a great intro to xajax. If you're browsing around to pick an AJAX library that suits you best, this is a must post to check out.

On a different note, apparently Marco never sleeps, because he just finished a theme for a Typo contest (Typo is a blogging software, very AJAX-rich) and his blog just became a part of the 9rules network. Keep an eye on this guy (and that rhymes! :) ) as I get the feeling we're going to see more from him in the coming months. And that doesn't mean you shouldn't consult his past posts, because you should, great stuff there.

And on a completely different note - I was this close of carrying the family name "Markov", my father's family name used to be Markov after a grand-grand-...-grand-father whose first name was Marko (or Marco) but my father changed his name to Stefanov. This close... :D

 

The Invisible Ad

Tuesday, November 15th, 2005

Launched TheInvisibleAd.com today. It's my version of the amazing Million Dollar Homepage and is mostly JavaScript muscle flexing ;) There is a little PHP, but very little, some style work and some AJAX/XML. But most of it is the JavaScript.

Will share the implementation details here, watch this space. There were a few issues to resolve ... trying to dynamically create 75 * 42 nodes in a DOM tree is one example.

Again - http://www.theinvisblead.com.

 

WebConsole - Take command (line) with AJAX

Friday, October 14th, 2005

My article describing how to create a simple Javascript XMLHTTP application is now featured on SitePoint. How cool is that!

A