Next Image
Make the current image sticky.
Previous Image
randys.org - randys.org

Posts Tagged ‘javascript’

Prototype: It’s Not Just a JavaScript Library

Used to be that writing front-end code (HTML, CSS, JavaScript) wasn’t terribly complex. The syntax of HTML and CSS isn’t all that difficult to get the hang of and JavaScript (back in the day) was just a tool to validate form fields and play funny tricks on poor unsuspecting visitors. These days, JavaScript has become the language for front-end development and it’s not just for printing the ‘lastModifiedDate’ of a document.

Anyone who has kept up with the advancements of JavaScript knows the Prototype library. For those who don’t know, it’s a JavaScript library that wraps a whole bunch of functionality into easy to use (and remember) “shortcuts” for doing things like getting elements on a page, manipulating said elements, and dealing with data. It’s all written in JSON notation and allows you do things like:

$('element-id').addClassName('active').show();

Instead of

var element = document.getElementById('element-id');
    element.className = 'active';
    element.style.display = 'block';

Anyway, things like Prototype, jQuery, Dojo, and YUI all provide some convenience to writing custom JavaScript applications. I haven’t dug super deep into any of the frameworks’ source (mostly because the code has been somewhat obfuscated and “compressed” to save space), but I imagine that they all have one thing in common; they make use of the prototype property to extend both existing and custom built objects/classes in JavaScript.

The prototype Property

Even if you don’t make heavy use of one of the afforementioned framework/toolkits, using the prototype property to extend existing JavaScript objects and/or classes can be quite useful. Say you want an easy way to print out a date. Rather than createing a separate function, just extend the Date object itself.

Date.prototype.months = new Array(
    {name: "January",   abbrev: "Jan", number: "01"},
    {name: "February",  abbrev: "Feb", number: "02"},
    {name: "March",     abbrev: "Mar", number: "03"},
    {name: "April",     abbrev: "Apr", number: "04"},
    {name: "May",       abbrev: "May", number: "05"},
    {name: "June",      abbrev: "Jun", number: "06"},
    {name: "July",      abbrev: "Jul", number: "07"},
    {name: "August",    abbrev: "Aug", number: "08"},
    {name: "September", abbrev: "Sep", number: "09"},
    {name: "October",   abbrev: "Oct", number: "10"},
    {name: "November",  abbrev: "Nov", number: "11"},
    {name: "December",  abbrev: "Dec", number: "12"}
);
Date.prototype.dow = new Array(
    {name: 'Sunday',    abbrev: 'Sun', number: "01"},
    {name: 'Monday',    abbrev: 'Mon', number: "02"},
    {name: 'Tuesday',   abbrev: 'Tue', number: "03"},
    {name: 'Wednesday', abbrev: 'Wed', number: "04"},
    {name: 'Thursday',  abbrev: 'Thu', number: "05"},
    {name: 'Friday',    abbrev: 'Fri', number: "06"},
    {name: 'Saturday',  abbrev: 'Sat', number: "07"}
);
Date.prototype.getShortDate = function() {
    return this.months[this.getMonth()].abbrev + ' ' + this.getDate() + ' ' + this.getFullYear();
};
Date.prototype.getLongDate = function() {
    return this.dow[this.getDay()].name + ', ' + this.months[this.getMonth()].name + ' ' + this.getDate() + ', ' + this.getFullYear();
};
Date.prototype.getValueDate = function() {
    var d = (this.getDate() < 10) ? '0'+this.getDate():this.getDate();
    return this.getFullYear() + '/' + this.months[this.getMonth()].number + '/' + d;
};

var now = new Date();
document.write(now.getLongDate());

And you get something like this . Handy.

Now, there’s a couple of issues with the above script. One, the names aren’t localized and two, there’s probalby a more efficient way to formatting a date (much like the example on this page). But, it works in all the browsers I tested (Chrome, Firefox, IE7, Safari [Mac]).

You can prototype most of the default objects in JavaScript. Say you have an application the has to validate a bunch of text fields. Prototype the String objects to add built in parsing methods for various fields.

String.prototype.isValidEmail = function() { ... }
String.prototype.isValidPhone = function() { ... }

You get the idea.

The prototype property is a handy little tool. There maybe some limitations between browsers, but overall, it should help simplify your code and prevent repetitive and reduntant methods.

• • •

Scrobble This: last.fm recent tracks AJAX style

So, I’ve been reading up a bit on prototype.js and its Ajax helpers. It’s an amazing tool and helped me write the bit of info at the top of the page. It’s pretty basic, but here’s the code that does most of the work:

function lastfm()
{
    new Ajax.Request('/as/recenttracks.xml',
    {
        method: 'get',
        onLoading: function() {

    },
    onLoaded: function(transport) {
        if (transport.overrideMimeType) {
            transport.overrideMimeType('application/xml');
        }
    },
    onSuccess: function(transport) {
        var response = transport.responseXML.documentElement;
        updateLastfm(response);
    },
    onFailure: failedLastfm()
});

}

The only issue I ran into was that I was originally using the RSS flavor of recent tracks, however it didn’t split up the artist and track information. It displays it as <title>[artist] – [track]</title>. That en-dash in the middle was preventing me from using title.split() on the JavaScript side of things. Really weird.

Also, since I’m a complete newbie with Ruby, I couldn’t figure out how (read: didn’t take the time to learn) to grab the content from a remote server and serve it up to the JavaScript. I’m sure it’s pretty simple… but I was at work and in a hurry. So, being that I know PHP, I just created a script to download the file and save it to the local disk and setup a cronjob.

Here’s the PHP script:

class lastfm
{
    private $user;
    private $reports;
    private $basews;
    public $saveto;

function __construct($user)
{
    $this-&gt;user = $user;
    $this-&gt;basews = 'http://ws.audioscrobbler.com/1.0/user/';
    $this-&gt;reports = array(
        'recenttracks.xml',
        'weeklyartistchart.xml',
        'weeklytrackchart.xml',
        'topartists.xml'
    );
    $this-&gt;saveto = '.';
}

public function go()
{
    for ($i = 0; $i &lt; count($this-&gt;reports); $i++)
    {
        try
        {
            $opts = array('http' =&gt; array('method' =&gt; 'GET', 'header' =&gt; 'Content-type: text/plain; charset=utf-8'));
            $context = stream_context_create($opts);

            $fp = fopen($this-&gt;saveto.DIRECTORY_SEPARATOR.$this-&gt;reports[$i], 'w+');
            $stream = fopen($this-&gt;basews.$this-&gt;user.'/'.$this-&gt;reports[$i], 'r', false, $context);
            $string = stream_get_contents($stream);
            fwrite($fp, $string);
            fclose($fp);
            fclose($stream);
            echo 'Saved ' . $this-&gt;saveto.DIRECTORY_SEPARATOR.$this-&gt;reports[$i] . "\n";
        }
        catch (Exception $e)
        {
            echo $e-&gt;getMessage() . "\n";
        }
    }
}

public function setSaveto($path)
{
    if (is_dir($path))
    {
        if (ereg('\/$', $path))
        {
            $path = ereg_replace('\/$', '', $path);
        }
        $this-&gt;saveto = $path;
    }
    else
    {
        $this-&gt;createDir($path);
        $this-&gt;setSaveto($path);
    }
}

private function createDir($path)
{
    if (!is_dir($path))
    {
        $res = `mkdir -p $path`;
    }
}

}

I’ll hit up the Rails API Docs one of these days and write a simple Ruby script that does all the work of the PHP script. Even better would be to process the XML document using ruby that just returns a string of HTML and use Ajax.PeriodicalUpdater($(e), ...).

• • •

All content Copyright © 1999 — 2010 Randy Sesser | Happily Hosted by WebFaction
Entries (RSS) | Comments (RSS)