Most read posts this month



Mar 11th 2010 × porting element storage from mootools 1.2 to 1.11 and 1.1.2

This is a very nice feature, one of the great ideas that came with mootools 1.2. You can store any property within elements by simply mimicking the markup of <div myprop=”myvalue”> in javascript. However, setting such proprietary element properties in IE can be very slow. What mootools 1.2 did was to abstract element storage into a global object with the elements’ UID as key. Very smart, particularly as it allows for storing not only simple text assignments but even references to classes / instances, arrays and so forth.

Unfortunately, some of us (like the Joomla users) are stuck with using mootools 1.1.x for the time being and cannot take advantage of the element storage system. I am so used to keeping data contextual to elements within their storage that I ported the whole thing from 1.2. Here is all you need to achieve the .store and .retrieve element methods:

(function() {
    // compatibility layer with mootools 1.2 element storage system
    // scoped
    var storage = {}, Native = {
        UID: 1
    };

    var $uid = (window.ie) ? function(item){
        return (item.uid || (item.uid = [Native.UID++]))[0];
    } : function(item){
        return item.uid || (item.uid = Native.UID++);
    };

    var get = function(uid){
        return (storage[uid] || (storage[uid] = {}));
    };

    Element.extend({
        retrieve: function(property, dflt){
            if (!this.uid)
                $uid(this);

            var storage = get(this.uid), prop = storage[property];
            if (dflt != undefined && prop == undefined) prop = storage[property] = dflt;
            return $pick(prop);
        },
        store: function(property, value){
            if (!this.uid)
                $uid(this);

            var storage = get(this.uid);
            storage[property] = value;
            return this;
        }
    });
})();

To see this in action, play with my simplified jfiddle example below:


Mar 10th 2010 × Cross-domain AJAX calls via YQL as proxy and mootools JSONP

I wrote this a while back when I needed to do pseudo AJAX calls to a remote host. Due to XSS restrictions and security policies, a normal XMLHttpRequest (XHR) call is not allowed to work across domains or even sub-domains. But Yahoo’s YQL interface kindly lets you GET any URL (which also means being able to submit via GET), irregardless of whether the domain is local or not.

Here is how it works. You need mootools (also download mootools-more as this class will extend Request.JSONP which is a part of mootools-more).

Request.YQLajax = new Class({
    // gets basic info such as country and latitude data
    Extends: Request.JSONP,
    options: {
        log: !true,
        url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22{location}%22&format=xml"
    },
    initialize: function(location, options) {
        this.parent(options);
        if (!location)
            return;

        this.options.url = this.options.url.substitute({location: encodeURIComponent(location)});
    },
    success: function(data, script) {
        this.parent(data, script);
    }
});

// example use to fetch BBC's page
new Request.YQLajax("http://www.bbc.co.uk/", {
    onSuccess: function(data) {
        $("result").set("html", data.results);
    }
}).send();

You can see this in action on mooshell or play with it below. Happy cross-domain ajax-ing.


Mar 4th 2010 × Getting latest tweets through mootools JSONP

Nothing like being egocentric so here’s what you can do to add latest tweets of a particular user to your site through mootools. This class totally `forked` from a post by AppDen (Scott Kyle) so feel free to give him some love, he deserves it for being such a bright spark. You can also “play” with this live on JSFiddle

Request.twitterAPI = new Class({
    // return json data with latest tweets form a particular user
    Extends: Request.JSONP,
    options: {
        target: $empty(),
        tweetBits: {
            textClass: "tweetBody",
            dateClass: "tweetDate"
        },
        maxTweets: 4,
        autoLink: true,
        url: "http://twitter.com/statuses/user_timeline/{user}.json"
    },
    initialize: function(user, options) {
        this.parent(options);
        this.options.url = this.options.url.substitute({user: user});
        this.element = document.id(this.options.target);
        if (!this.element)
            return;

        this.element.set("html", "Loading tweets...");
    },
    success: function(data, script) {
        this.element.empty();
        this.parent(data, script);
    },
    showPost: function(post) {
        var creationDate = Date.parse(post.created_at).format("%x %X");
        new Element("div", {
            "class": this.options.tweetBits.textClass,
            "html": this.options.autoLink ? this.linkify(post.text) : post.text
        }).adopt(new Element("div", {
            "class": this.options.tweetBits.dateClass,
            "html": creationDate // + " via " + post.source.replace("\\",'')
        })).inject(this.element);
    },
    addPosts: function(response) {
        if (!response.length || !this.element)
            return;

        response.each(function(post, i) {
            if (i < this.options.maxTweets)
                this.showPost(post);
        }.bind(this));
    },
    linkify: function(text){
        // modified from TwitterGitter by David Walsh (davidwalsh.name)
        // courtesy of Jeremy Parrish (rrish.org)
        return text.replace(/(https?:\/\/[\w\-:;?&=+.%#\/]+)/gi, '$1')
            .replace(/(^|\W)@(\w+)/g, '$1@$2')
            .replace(/(^|\W)#(\w+)/g, '$1#$2');
    }
});

// create an instance
new Request.twitterAPI("D_mitar", {
    target: "myTweets", // target element to 'host' the tweets
    onComplete: function(data) {
        this.addPosts(data); // add all posts to element.
    }
}).send();

Additionally, you can style the tweets by using 2 classes for the element:

div.tweetBody {
    line-height: 1.1;
    font-family: arial;
    font-size: 12px;
    margin-bottom: 10px;
}

div.tweetDate {
    font-size: 10px;
    color: #500;
    text-align: center;
    padding-top: 4px;
}

That’s it, it’s that simple. Happy tweeting.


Feb 19th 2010 × javascript tests fun continues

A great new test through javascript.ru (an incredible resource, even if in Russian). Dmitry Soshnikov has created a new fun javascript quiz you can test your knowledge against. The difference is that he’s tried to abstract real world problems, collected from various mailing lists or problems of his own doing. Worth 10 mins for sure.


Feb 15th 2010 × Creating a wrapper namespace for the FireBug console.log function for IE and other browsers

Most web application/AJAX development takes place within the confines of either FireFox + Firebug or Webkit browsers and their consoles (firebug is now available on chrome?). However, other browsers (such as IE) lack console functionality and this presents a problem.

When in a hurry / under pressure, I have been known to forget to take out a console reference out of code that sneaks it’s way into the production environment. If not immediately noticeable, tucked away behind a loop / if statement, you’d never know about it… That is, until the error reports start flooding in.

Not wanting to find myself in such position again, I decided to write a little wrapper that can cater for nearly all of firebug’s console methods. The most common ones, such as console.log, console.info, console.clear and console.count are pre-defined but you can use the model and add others into the singleton. Check this fine firebug cheatsheet for more ideas on other methods you may want to port.

var $C = {
    // console wrapper by D. Christoff @ http://fragged.org/
    _version: 2.1.3,
    debug: true, // global debug on|off
    quietDismiss: false, // may want to just drop, or alert instead,
    method: "log",
    _hasConsole: function(_method) {
        var _method = _method || "log";
        return typeof(console) == 'object' && typeof(console[_method]) != "undefined";
    },
    _consoleMethod: function() {
        if (!this.debug) return false;

        if (this._hasConsole(this.method)) {
            try {
                console[this.method].apply(this, arguments);
            } catch(e) {
                // safari console may not accept scope like so
                for (var i = 0, l = arguments.length; i < l; i++)
                    console[this.method](arguments[i]);
            }
        } else if(!this.quietDismiss && arguments.length) {
            var result = "";
            for (var i = 0, l = arguments.length; i < l; i++)
                result += arguments[i] + " ("+typeof arguments[i]+") ";

            alert(result);

        }
    },
    log: function() {
        this.method = "log";
        this._consoleMethod.apply(this, arguments);
    },
    info: function() {
        this.method = "info";
        this._consoleMethod.apply(this, arguments);
    },
    clear: function() {
        this.method = "clear";
        this._consoleMethod.apply(this);
    },
    count: function() {
        this.method = "count";
        this._consoleMethod.apply(this, arguments);
    },
    debug: function() {
        this.method = "debug";
        this._consoleMethod.apply(this);
    }
}; // end console wrapper.

// example data and object
$C.clear();
var foo = "foo", bar = document.getElementById("divImage");
$C.log(foo, bar);
$C.count("loop");
$C.info("we are inside a loop!");
$C.count("loop");

The interface is simple, just use the "$C" namespace (name it what you like) instead of "console" will have the preserved functionality / results within FireFox, whereas IE users can either see an alert pop-up dialogue or nothing at all (if $C.quietDismiss = true).

// To disable the alerts in IE, do
$C.quietDimiss = true;
// To disable debug completely:
$C.debug = false;

I hope somebody finds this useful...

update history

*update* thanks to divide by zero for the improvement - in this post.

*update again* this is a fix from the previous update, seems that safari's console cannot accept scoping through apply so I added a try {} catch {} block where it reverts to the old loop

*update again (15/02/10)* modded to support any possible console method with ease


Feb 15th 2010 × on performance of looping arrays and objects in javascript

There are probably as many ways of looping an array in javascript as there are phrases that are synonymous for masturbation. So, what are they and how fast do they perform? Head over to this test @ a blog on Sun which sports no less than 17 different loops to get a fair indication of how fast things work in today’s browsers.

Disappointingly, the native array.forEach in my firefox 2.5 seems to be one of the worst results. while(length–) { … } ftw!


Feb 14th 2010 × Detect adblocking software through mootools and have a fallback strategy

Being able to check if website adverts were blocked is of some importance. As browser plugins such as AdBlock Plus and the likes are getting better all the time, less and less of your adverts get served up. Hence, my simple solution that can try and recover some of the lost revenue.

Google adwords code can be wrapped into a plain DIV tag without a set width/height, letting any content injected into it by Google dictate its size. Through a basic Element prototype shortcut, called Element.adCheck(), you can check if the size has remained less than expected (aka, the AD got blocked).

Element.implement({
    adCheck: function(options) {
        var options = $merge({
            delay: 3000,
            message: "<center>It looks as if my Adwords did not display<br />I am just a programmer that needs to feed their hungry child and wife, please disable AdBlock or whatever clever advert blocking software you are running on my site.</center>",
            minHeight: 20,
            minWidth: 20
        }, options);

        this.store("timer", (function() {
            var coords = this.getCoordinates();
            if (coords.height.toInt() < options.minHeight || coords.width < options.minWidth) {
                this.set("html", options.message).fade(0, 1)
            }
        }).delay(options.delay, this));
        return this;
    }
});

// check it for a div with id="as":
$("as").adCheck();

// check it for all divs with class 'myads'
$$("div.myads").adCheck({message: 'please disable adblock'});

// use alternative adverts instead
$("as").adCheck({message:"<a href='/signup.php'><img src='/img/signupbanner.gif'>"});

To run this, you need mootools 1.2+ core only. You could also extend the above code to .pass() a function callback so you can execute a proper ‘onAdvertFailed’ event.

Just a thought, but wouldn’t it be nicer if AdSense could serve adverts through JSONP that you can parse and embed clientside? It won’t be mainstream but it could really screw with current AdBlocking methods…


Feb 9th 2010 × interviewing for javascript developers and advanced javascript tests

We’re shortly due to hire a new lamp/javascript developer at work and I just came across a very interesting post by Nicholas C. Zakas of Yahoo and O’Reilly fame. Although his requirements are probably a bit excessive (considering the enterprise level he’s at), I think there are some good ideas – definitely worth a read if you ever want to partake in the ‘big time’. Link here. Another interesting post explaining this javascript test offers some great insights into the workings of ECMA / javascript.

If you find the test by Dmitry Baranovsky easy to cope with, have a go at this one by Juriy Zaytsev of Prototype core dev team, some nasties there but it’s laced with knowledge of the inner workings of javascript. Is it fair to expect somebody you are interviewing to solve these, that’s a different subject…


Nov 24th 2009 × Lemmings javascript sprite animation with pseudo parallax (through mootools)

This was supposed to be my Friday Fun post but it got to where it’s at on the following Monday instead. Having never tackled sprite animation before, this has been a learning experience anyway (on the principles of animation also).

I think the result is fairly adequate – a moving lemming in a world that changes atmospheric effects dependent on the time of day, complete with parallax-like effect relative as counter to the lemming’s movement.

Oh, yes. The lemming can also be quite moody–hates being bothered. Which is fine, you can blow him up too. Enjoy and click below:
lemmings parallax animation screenshot

P.S. This will feature as the header of fragged.org’s new wordpress theme which is almost completed now. So, a little taster of things to come…
P.P.S. Thanks to crisp for the original DHTML lemmings and to holy.pt for his vigorous testing and advice.


Nov 18th 2009 × Snow flakes for your site? Try mooSnow – a javascript class that just snows

Just pulled out the old textSnow class foer 1.11 and rewrote it for 1.2.4. Anyway, head over to the demo page, it has all the info you need.