Category Archives: javascript

A Quick Simple Way to Download All the Images on a Page

You don’t need to write a web scraper to do this, just some simple code and standard linux/unix commands.

  1. Open the page in your web browser
  2. Open the Developer Tools
  3. Paste in the following Javascript
var images = document.getElementsByTagName('img'); 
var srcList = [];
for(var i = 0; i < images.length; i++) {
    srcList.push(images[i].src.split('?', 1)[0]);
}
srcList.join('\n');
  1. Create a folder to store the images
  2. Copy the text output from above into a file & save as images.txt in your folder
  3. Inspect images.txt to make sure it looks right
  4. Run the following commands in a terminal, from your folder
cat images.txt | sort | uniq > uniq_images.txt
wget -i uniq_images.txt

Now all the images from that page should be in the folder you created.

jQuery Validation with Django Forms

Django has everything you need to do server-side validation, but it’s also a good idea to do client-side validation. Here’s how you can integrate the jQuery Validation plugin with your Django Forms.

jQuery Validation Rules

jQuery validation works by assigning validation rules to each element in your form. These rules can be assigned a couple different ways:

  1. Class Rules
  2. Metadata Rules
  3. Rules Object

Django Form Class Rules

The simplest validation rules, such as required, can be assigned as classes on your form elements. To do this in Django, you can specify custom widget attributes.

from django import forms
from django.forms import widgets

class MyForm(forms.Form):
    title = forms.CharField(required=True, widget=widgets.TextInput(attrs={
        'class': 'required'
    }))

In Django 1.2, there’s support for a required css class, but you can still use the technique above to specify other validation rules.

Django Form Metadata Rules

For validation methods that require arguments, such minlength and maxlength, you can create metadata in the class attribute. You’ll have to include the jQuery metadata plugin for this style of rules.

from django import forms
from django.forms import widgets

class MyForm(forms.Form):
    title = forms.CharField(required=True, minlength=2, maxlength=100, widget=widgets.TextInput(attrs={
        'class': '{required:true, minlength:2, maxlength:100}'
    }))

jQuery Validate Rules Object

If your validation requirements are more complex, or you don’t want to use the metadata plugin or class based rules, you can create a rules object to pass as an option to the validate method. This object can be generated in your template like so:

<script type="text/javascript">
FORM_RULES = {
    '{{ form.title.name }}': 'required'
};

$(document).ready(function() {
    $('form').validate({
        rules: FORM_RULES
    });
});
</script>

The reason I suggest generating the rules object in your template is to avoid hardcoding the field name in your javascript. A rules object can also be used in conjunction with class and metadata rules, so you could have some rules assigned in individual element classes or metadata, and other rules in your rules object.

Error Messages

If you want to keep the client-side validation error messages consistent with Django’s validation error messages, you’ll need to copy Django’s error messages and specify them in the metadata or in a messages object.

Metadata Messages

Messages must be specified per-field, and per-rule. Here’s an example where I specify the minlength message for the title field.

from django import forms
from django.forms import widgets

class MyForm(forms.Form):
    title = forms.CharField(minlength=2, widget=widgets.TextInput(attrs={
        'class': '{minlength:2, messages:{minlength:"Ensure this value has at least 2 characters"}}'
    }))

Messages Object

Messages can also be specified in javascript object, like so:

<script type="text/javascript">
FORM_RULES = {
    '{{ form.title.name }}': 'required'
};

FORM_MESSAGES = {
    '{{ form.title.name }}': 'This field is required'
};

$(document).ready(function() {
    $('form').validate({
        rules: FORM_RULES,
        messages: FORM_MESSAGES
    });
});
</script>

Just like with validation rules, messages in element metadata can be used in conjunction with a global messages object. Note: if an element has a title attribute, then the title will be used as the default error message, unless you specify ignoreTitle: false in the jQuery validate options.

Error Labels vs Errorlist

Django’s default error output is an error list, while the default for jQuery Validation errors is a label with class="error". So in order to unify your validation errors, there’s 2 options:

  1. make jQuery Validation output an error list
  2. output error labels instead of an error list in the template

Personally, I prefer the simple error labels produced by jQuery validation. To make Django generate those instead of an error list, you can do the following in your templates:

{{ field }}
{% if field.errors %}
{# NOTE: must use id_NAME for jquery.validation to overwrite error label #}
<label class='error' for='id_{{ field.name }}' generated="true">{{ field.errors|join:". " }}</label>
{% endif %}

You could also create your own error_class for outputting the error labels, but then you’d lose the ability to specify the for attribute.

If you want to try to make jQuery validation produce an error list, that’s a bit harder. You can specify a combination of jQuery validation options and get a list, but there’s not an obvious way to get the errorlist class on the ul.

$('form').validate({
    errorElement: 'li',
    wrapper: 'ul'
});

Other options you can look into are errorLabelContainer, errorContainer, and a highlight function.

Final Recommendations

I find it’s easiest to specify class and metadata rules in custom widget attributes 90% of the time, and use a rules object only when absolutely necessary. For example, if I want to require only the first elements in a formset, but not the rest, then I may use a rules object in addition to class and metadata rules. For error messages, I generally use a field template like the above example that I include for each field:

{% with form.title as field %}{% include "field.html" %}{% endwith %}

Or if the form is really simple, I do

{% for field in form %}{% include "field.html" %}{% endfor %}

Useful jQuery Plugins

Inline Form Labeling
Form Validation
Modal Windows
Misc

Design Patterns in Javascript – Model-View-Controller

Model-View-Controller, or MVC for short, is an software architecture pattern for user interfaces that creates a distinction between the display (or view), the data (or model), and the interaction (or controller). In this article, I’m going to focus specifically on how MVC applies to the client side of web applications. What I mean is that MVC in a web based ui translates to

This separation of concerns means that as long as the model stays consistent, you can

  1. Create multiple views for the same model
  2. Develop the controller and views independently

For a great example of 1 checkout css Zen Garden. Here, the same HTML (the model) can be seen with many different views.

Now checkout the jquery ui demos for a clear example of both 1 and 2. Again, the same HTML has many different views with the various CSS themes, and you can also see jquery ui controller code in action. The Javascript manipulates the model, affecting what you see and how you see it, independently of which theme (or view) you choose.

What this all means is that you can create semantically correct HTML optimized for search engines, CSS so your page looks good for humans, and Javascript to make your page interactive. In other words, content can be separated from presentation, which can be separated from the interaction behavior. The CSS and Javascript can be developed (mostly) independently and only be loosely coupled to the HTML.

Taking this a step further, it’s possible to create generic views and controllers using CSS and Javascript that work on a small generic model. jquery ThickBox is an example of this, since it can be used on any page where you have <a class='thickbox' ...>...</a>. As long as your HTML supports the generic model, you can reuse the CSS and Javascript across multiple pages.

jQuery UI Sortable Tabs with Accordions

It’s possible to combine jQuery UI elements with each other. For example, you can create tabs that contain accordions. And then you can make those tabs sortable. Of course, your html has to fit the expected pattern.

Accordion HTML

The accordion html is generally a <div> with pairs of child elements. The first element of the pair is the header and the second is the content. I usually use heading elements like <h3> for the headers because otherwise the accordions won’t stack nicely. If you’re not sure what I’m talking about, try making an accordion using just <a> tags for the headers.

<div>
    <h3><a href='#'>Section1</a></h3>
    <div><p>section 1 content</p></div>
    <h3><a href='#'>Section2</a></h3>
    <div><p>section 2 content</p></div>
    <h3><a href='#'>Section3</a></h3>
    <div><p>section 3 content</p></div>
</div>

Tabs HTML

The tabs html is generally a <div> with a <ul> containg a <li> for each tab header, followed by one content <div> for each tab. Each tab <li> should contain an <a> whose href refers to a content <div>.

<div>
    <ul>
          <li><a href='#tab1'>Tab 1</a></li>
          <li><a href='#tab2'>Tab 2</a></li>
          <li><a href='#tab3'>Tab 3</a></li>
     </ul>
     <div id='tab1'>tab1 content</div>
     <div id='tab2'>tab2 content</div>
     <div id='tab3'>tab3 content</div>
</div>

Sortable HTML

The sortable html is generally a simple list of elements.

<ul>
    <li><a href='#'>Item 1</a></li>
    <li><a href='#'>Item 2</a></li>
    <li><a href='#'>Item 3</a></li>
</ul>

Combining with jQuery UI

As you can see, the tabs html looks very similar to the sortable html, while the accordion html is quite different. The result is that it’s a bit tricky to create sortable accordions, but fairly easy to create sortable tabs. You can also combine tabs with accordions, and below I demonstrate how to put accordions within sortable tabs. For a working demo, checkout Sortable Tabs with Accordions. As for the question of why anyone would want to do this, I’ll leave that as an exercise for the reader 🙂

<html><head>
    <link rel="stylesheet" type="text/css" href="smoothness.css"; />
    <script src="jquery-1.3.2.min.js" type="text/javascript"></script>
    <script src="jquery-ui-1.7.2.custom.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    $(document).ready(function() {
        $('#tabs').tabs();
        $('#sortable').sortable({
            items: 'li'
        });
        $('.accordion').accordion({
            autoHeight: false,
            clearStyle: true,
            header: 'h3'
        });
    });
    </script>
</head>
<body>
<div id='tabs'>
    <ul id='sortable'>
        <li><a href='#tab1'>Tab 1</a></li>
        <li><a href='#tab2'>Tab 2</a></li>
        <li><a href='#tab3'>Tab 3</a></li>
    </ul>
    <div id='tab1'>
        <div class='accordion'>
            <h3><a href='#'>Section1</a></h3>
            <div><p>section 1 content</p></div>
            <h3><a href='#'>Section2</a></h3>
            <div><p>section 2 content</p></div>
            <h3><a href='#'>Section3</a></h3>
            <div><p>section 3 content</p></div>
        </div>
    </div>
    <div id='tab2'>
        <div class='accordion'>
            <h3><a href='#'>Section4</a></h3>
            <div><p>section 4 content</p></div>
            <h3><a href='#'>Section5</a></h3>
            <div><p>section 5 content</p></div>
            <h3><a href='#'>Section6</a></h3>
            <div><p>section 6 content</p></div>
        </div>
    </div>
    <div id='tab3'>
        <div class='accordion'>
            <h3><a href='#'>Section7</a></h3>
            <div><p>section 7 content</p></div>
            <h3><a href='#'>Section8</a></h3>
            <div><p>section 8 content</p></div>
            <h3><a href='#'>Section9</a></h3>
            <div><p>section 9 content</p></div>
        </div>
    </div>
</div>
</body></html>

jQuery and Usability Links

jQuery sliders:

jQuery tooltips:

Usability testing:

Misc:

Dates and Times in Python and Javascript

If you are dealing with dates & times in python and/or javascript, there are two must have libraries.

  1. Datejs
  2. python-dateutil

Datejs

Datejs, being javascript, is designed for parsing and creating human readable dates & times. It’s powerful parse() function can handle all the dates & times you’d expect, plus fuzzier human readable date words. Here are some examples from their site.

Date.parse("February 20th 1973");
Date.parse("Thu, 1 July 2004 22:30:00");
Date.parse("today");
Date.parse("next thursday");

And if you are programmatically creating Date objects, here’s a few functions I find myself using frequently.

// get a new Date object set to local date
var dt = Date.today();
// get that same Date object set to current time
var dt = Date.today().setTimeToNow();

// set the local time to 10:30 AM
var dt = Date.today().set({hour: 10, minute: 30});
// produce an ISO formatted datetime string converted to UTC
dt.toISOString();

There’s plenty more in the documentation; pretty much everything you need for manipulation, comparison, and string conversion. Datejs cleanly extends the default Date object, has been integrated into a couple date pickers, and supports culture specific parsing for i18n.

python-dateutil

Like Datejs, dateutil also has a powerful parse() function. While it can’t handle words like “today” or “tomorrow”, it can handle nearly every (American) date format that exists. Here’s a few examples.

>>> from dateutil import parser
>>> parser.parse("Thu, 4/2/09 09:00 PM")
datetime.datetime(2009, 4, 2, 21, 0)
>>> parser.parse("04/02/09 9:00PM")
datetime.datetime(2009, 4, 2, 21, 0)
>>> parser.parse("04-02-08 9pm")
datetime.datetime(2009, 4, 2, 21, 0)

An option that comes especially in handy is to pass in fuzzy=True. This tells parse() to ignore unknown tokens while parsing. This next example would raise a ValueError without fuzzy=True.

>>> parser.parse("Thurs, 4/2/09 09:00 PM", fuzzy=True)

It don’t know how well it works for international date formats, but parse() does have options for reading days first and years first, so I’m guessing it can be made to work.

dateutil also provides some great timezone support. I’ve always been surprised at python’s lack of concrete tzinfo classes, but dateutil.tz more than makes up for it (there’s also pytz, but I haven’t figured out why I need it instead of or in addition to dateutil.tz). Here’s a function for parsing a string and returning a UTC datetime object.

from dateutil import parser, tz
def parse_to_utc(s):
    dt = parser.parse(s, fuzzy=True)
    dt = dt.replace(tzinfo=tz.tzlocal())
    return dt.astimezone(tz.tzutc())

dateutil does a lot more than provide tzinfo objects and parse datetimes; it can also calculate relative deltas and handle iCal recurrence rules. I’m sure a whole calendar application could be built based on dateutil, but my interest is in parsing and converting datetimes to and from UTC, and in that respect dateutil excels.