Archive for the 'projects' Category

A better DateTime widget for Django

Monday, April 26th, 2010

I’m convinced that every Django developer has struggled with how to present DateTime fields to users.  We all know and love the widgets used in the Django admin, and emboldened by the Django developers,1 every new developer tries to just use those.  But each one discovers quickly that it’s not that simple — you have to link in CSS from the admin site that will screw with your layout, and even after you get it working on your test site, it will not deploy correctly to production.  So let me begin by saying:

Do not use the Django admin’s DateTime widget.

I spent the weekend working out how to do a split DateTime widget properly, and I’m pretty happy with the result, so I’ll share it here.  It uses a text field with a jQuery UI calendar picker for the date, and a simple widget for the time.  Here’s what it looks like:

And here’s the code:

fields.py

from time import strptime, strftime
from django import forms
from django.db import models
from django.forms import fields
from conflux.widgets import JqSplitDateTimeWidget

class JqSplitDateTimeField(fields.MultiValueField):
    widget = JqSplitDateTimeWidget

    def __init__(self, *args, **kwargs):
        """
        Have to pass a list of field types to the constructor, else we
        won't get any data to our compress method.
        """
        all_fields = (
            fields.CharField(max_length=10),
            fields.CharField(max_length=2),
            fields.CharField(max_length=2),
            fields.ChoiceField(choices=[('AM','AM'),('PM','PM')])
            )
        super(JqSplitDateTimeField, self).__init__(all_fields, *args, **kwargs)

    def compress(self, data_list):
        """
        Takes the values from the MultiWidget and passes them as a
        list to this function. This function needs to compress the
        list into a single object to save.
        """
        if data_list:
            if not (data_list[0] and data_list[1] and data_list[2] and data_list[3]):
                raise forms.ValidationError("Field is missing data.")
            input_time = strptime("%s:%s %s"%(data_list[1], data_list[2], data_list[3]), "%I:%M %p")
            datetime_string = "%s %s" % (data_list[0], strftime('%H:%M', input_time))
            print "Datetime: %s"%datetime_string
            return datetime_string
        return None

widgets.py

from django import forms
from django.db import models
from django.template.loader import render_to_string
from django.forms.widgets import Select, MultiWidget, DateInput, TextInput
from time import strftime

class JqSplitDateTimeWidget(MultiWidget):

    def __init__(self, attrs=None, date_format=None, time_format=None):
        date_class = attrs['date_class']
        time_class = attrs['time_class']
        del attrs['date_class']
        del attrs['time_class']

        time_attrs = attrs.copy()
        time_attrs['class'] = time_class
        date_attrs = attrs.copy()
        date_attrs['class'] = date_class

        widgets = (DateInput(attrs=date_attrs, format=date_format),
                   TextInput(attrs=time_attrs), TextInput(attrs=time_attrs),
                   Select(attrs=attrs, choices=[('AM','AM'),('PM','PM')]))

        super(JqSplitDateTimeWidget, self).__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            d = strftime("%Y-%m-%d", value.timetuple())
            hour = strftime("%I", value.timetuple())
            minute = strftime("%M", value.timetuple())
            meridian = strftime("%p", value.timetuple())
            return (d, hour, minute, meridian)
        else:
            return (None, None, None, None)

    def format_output(self, rendered_widgets):
        """
        Given a list of rendered widgets (as strings), it inserts an HTML
        linebreak between them.

        Returns a Unicode string representing the HTML for the whole lot.
        """
        return "Date: %s<br/>Time: %s:%s %s" % (rendered_widgets[0], rendered_widgets[1],
                                                rendered_widgets[2], rendered_widgets[3])

    class Media:
        css = {
            }
        js = (
            "js/jqsplitdatetime.js",
            )

/media/js/jqsplitdatetime.js

$(function() {
   $(".datepicker").datepicker({ dateFormat: 'yy-mm-dd' });
});

To use the field in a form, put something like the following into your form definition:

some_date_field = JqSplitDateTimeField(widget=JqSplitDateTimeWidget(attrs={'date_class':'datepicker','time_class':'timepicker'})

Finally, you need to put the jQuery UI code somewhere. Go get a custom jQuery UI package (I used all of UI Core and Interactions, the Datepicker widget, and Effects Core — your may want more or less depending on where else you’re using JQuery and JQuery UI), put the necessary files (the jQuery UI css and js, the jQuery js) somewhere accessible to your form. I’m using jQuery UI throughout my site, so I’ve got them in my base.html:

    <link type="text/css" href="/media/css/ui-conflux/jquery-ui-1.8.custom.css" rel="Stylesheet" />
    <script src="/media/js/jquery-1.4.2.min.js" type="text/javascript"></script>
    <script src="/media/js/jquery-ui-1.8.custom.min.js" type="text/javascript"></script>

But if you only need jQuery UI for this form, it might make sense to put these in the media class of the JqSplitDateTimeWidget along with jqsplitdatetime.js:

class Media:
   css = {
      "css/ui-custom/jquery-ui-1.8.custom.css"
   }
   js = (
      "js/jqsplitdatetime.js",
      "js/jquery-1.4.2.min.js",
      "js/jquery-ui-1.8.custom.min.js",
   )

A couple of caveats: this widget is not currently very customizable/internationalizable. It only deals with 12-hour time and I should probably pass the date format in as an argument. But it does the trick for what I need, and what a lot of U.S. developers will need, and these things are easily added (I’d love a patch!).

  1. “If you like the widgets that the Django Admin application uses, feel free to use them in your own application! They’re all stored in django.contrib.admin.widgets.” – The Django Form Media documentation []

FLOSS Dispenser: a free market for Android

Wednesday, February 10th, 2010

I’ve been working on developing a free software application market for Android.1 The obvious place to start was the SlideME Community Edition code, which as far as I know is the only existing free software project that does even part of the job. Unfortunately, SlideME’s Community Edition was abandoned due to “lack of community interest” in April 2008, several months before the first Android phones were even available. So most of the work I’ve done so far was to update the code to work with the current SDK, rework the interface to behave in a more standard way, and rewrite portions that relied on now-unavailable API elements.

FLOSS Dispenser (like SlideME) works in conjunction with a J2EE server application called JVending. JVending’s public repository was also abandoned by SlideME some time ago, so I’m maintaining a fork of JVending along with my fork of FLOSS Dispenser as a part of the Replicant project.

I put up build instructions for FLOSS Dispenser as well as for JVending; using these, you should be able to build both and have them work together. However, neither one is ready, which is why I’m not hosting an application store already. The FLOSS Dispenser code in particular is pretty buggy (most of them aren’t mine, but only because I haven’t written much of it), for one thing. For another, the system doesn’t yet facilitate GPL compliance — you can download and install apk binaries, but they don’t come with source code and license text. Until at least this feature exists, I don’t recommend anyone serve GPL’d apks to the public using JVending. Update: The client application is now in a working alpha state. The really bad bugs have been hammered out and source can be delivered with the apk (the mechanism for this is nonoptimal, but functional). The challenge now is to enable users of the server to submit new apps easily, and to enable admins to moderate them.

I wanted to have this and some other issues hammered out before I put the code up, but I was motivated by Jonathan Corbet’s recent LWN article on Android to just put up what I had and try to get some help. I know other people are interested in something like this, and though I’m hardly proud of the little coding I’ve done on this, it’s the best start we have for a free market.

So by all means, take a look and help me kick this thing out the door.

  1. The quick rationale for this is that the Android Market 1) is not itself free software, and 2) doesn’t enable you to search for applications by their license. []

New IdentiFox that plays nice with TwitterFox

Thursday, February 26th, 2009

IdentiFox is a Firefox addon to get Identi.ca updates.  It’s based on TwitterFox, and up till now you couldn’t use the two together, because they still shared certain unique identifiers in their code.  I spent some time reworking IdentiFox to solve this problem and generally clean up the Twitter references in the code. I created a whole new IdentiFox based on the latest TwitterFox Beta.  It now supports all of the following features:

  • Tab for private messages
  • #hashtags and !groups link back to their homes on http://identi.ca
  • Right-click menu enables copying, redenting, and viewing notice on http://identi.ca
  • New color scheme to match Identi.ca’s current design

I’m working on getting the Addon onto Mozilla’s site, but till then I’ll post the XPI here.  Please comment here or email me with any problems you run into!

  • Here is the source on bitbucket

Timely blog post fail (Halloween)

Wednesday, December 17th, 2008

Most years, Halloween sort of sneaks up on me — I don’t know what I’m going to do till the last minute, and I don’t bother thinking up a costume till the week before. But then I have to come up with something that I think is clever, or I’ll be sorely disappointed with myself, so I spend an entire day sorting out the minutia of whatever costume I pick. For my space drag costume, that was stringing together CDs with dental floss to make a skirt; for scrabble, it was gluing 225 little squares of felt to my t-shirt.

Which brings us to 2008. My girlfriend being a champion knitter and I being a champion nerd, we spied an opportunity to combine forces wonder-twins-like and make costumes involving knitting and computers.  The thing is, that Venn diagram yields little overlap indeed.  Eventually we settled on a Robot Prom theme — Carly would knit us vintage apparel and I would make it blink. And we even got started almost 3 months before Halloween. It just turns out that 3 months isn’t enough for Robot Prom.

Now, Carly pretty much knew what she was getting into.  She chose challenging patterns and was working uphill against a law school schedule, but she’s knit entire dresses (and sculptures) before.  Me, I’ve programmed plenty, but before August I had never built a single circuit, much less two wearables with multiple inputs and outputs communicating wirelessly.  But that’s what I was going to do, I thought — our costumes were supposed to blink/pulse/whatever slowly and dimly when Carly and I were far apart, and then start spazzing out when we were close together.  We realized that were were basically setting out to make costumes about how we’re an obnoxious, shmoopy couple (with LIGHTS!) but seriously, computers and knitting… there’s just not much you can do.

So Carly started knitting and I started reading and building simple circuits with my new Arduino Diecimila, but the going was pretty slow on my end.  I was making all of the rookie mistakes that anyone new to physical computing makes, including burning out two XBee radios by connecting them to 5 volts (they’re spec’d for a maximum of 3.6) and breaking a multimeter by doing I’m-not-sure-what.  Eventually, realizing that signal strength was not a reliable or fluid indicator of distance between radios, I ditched the S.O.-proximity-meter idea and just decided that our costumes would each have buttons and dials for controlling the light display on the other.  Even so, it wasn’t till a week before Halloween that I had barebones prototypes working and communicating with each other, and those were on breadboards with good old reliable copper wires… I had to make them work on cotton fabric using conductive thread.

We didn’t actually start working on combining our work until the day of our first halloween party, the day before halloween.  I took the day off with the intention of sewing like the wind.  But it turns out I can’t even thread a needle, much less sew, much less sew like something fast or atmospheric.  In a great stroke of luck, my wearable-electronics-ninja friend Grace stopped by for lunch that day, just as I was beginning to get a sense of how totally screwed I was.  She provided such life-saving pointers as: how to keep traces of conductive thread from touching; if the thread touches your skin you will short your circuit; omg you’re totally screwed.

For the rest of the day, Carly and I sewed until our fingers shook and our eyes wouldn’t focus, but we only finished most of her circuit and almost none of mine before it was past time to go to the party.  We knew we had to stop there, but we couldn’t even tell if hers worked at all, because it wasn’t designed to do anything without input from mine, so I quickly reprogrammed it to simplify its functionality (just one tri-color LED in her corsage, and no user control) and cut out the radio entirely. And by god, gutted as it was, it worked.  The little light in Carly’s (beautiful, expertly knit) corsage pulsed different colors.  She didn’t look like a robot, and I didn’t look like anything, but something worked.  So we went to the party and looked like this:

Our sad unfinished costumes at the NYU Law Fall Ball (my sign says Ambitious Costume Fail)

Carly’s corsage went nyeer-nyeer-nyeer (video)

But that’s about it.  The next day (Halloween), Carly spent all day sewing again, and I joined in as soon as I could, but by the time we had to leave, we were still missing pieces from the costumes, and the radios weren’t working (at one point I thought I actually destroyed my whole costume by connecting my Lilypad to 9v, but I got lucky).  So again we had to cut back on functionality, but at least this time we both had blinky lights and buttons and knobs to control them.  Also, we bought some silver face paint so that when people asked us what we were, we could say “Robot Prom!” without having to put “well, we were supposed to be…” in front of it.  All told, it still didn’t make any damn sense but at least it looked like a Halloween costume:

Our much-improved costumes of Halloween proper

We lost a lot of sleep, I broke some electronics, we had to explain our costumes to everyone, and by the end of the process we weren’t having any fun at all.  But on the other hand I got this sweet vest out of the deal and we didn’t break up.  And isn’t that what really matters?

Some more pictures:

The table covered in all our crap Furious sewing Testing Carly\'s corsage

The table covered in all our crap

Furious sewing

Testing Carly’s corsage

My DIM weekend: spice racks and camera lenses

Monday, September 22nd, 2008

Finally got my hands on a glue gun today and put together the magnetic spice rack that’s been on my todo list for a few weeks.  I got the materials list from here, but it probably originally came from here.  Basically, you hot-glue magnets to the back of watchmaker tins and fill them with spices, and you get a pretty and convenient way to store your spices, like so:

Magnetic spice rack on my fridge

I’m pretty happy with it, but the instructions leave out a few important details.  First, the hot glue doesn’t bond well to the magnets or the tins if they’re cold — like the glue gun manual says, you’ve got to heat metal before you can effectively hot-glue it.  You could do this by leaving them out in the sun or under a hot lamp.  I didn’t have either option today, so I laboriously heated the magnets and tins with my soldering iron.  I also used “super strength” hot glue, which seems to work better than the garden variety.  Also, I’m no physicist, but I’m pretty sure you can’t just glue either side of the magnet to the tin — if you use the wrong side it won’t stick to the fridge nearly so well.

Also, the watchmaker tins are a clever hack, but they’re not that well suited to the purpose.  The lids are made to lift off without much resistance, so I ended up gently bending the sides of the lids in to keep them from popping off unbidden.  For this same reason, you have to be careful when pulling them off the fridge — if you grab them by the lid, Roomba will be sucking more than his share of allspice.  Screw-off lids would work better.  I would also prefer larger tins (you can get them one size larger) — these don’t hold much more than a couple of tablespoonfuls of spice, so you’ll be refilling your chili and curry powder pretty frequently.  But larger tins would be heavier and would probably require stronger magnets, which would (Catch-22) make the tins pretty tough to pull off of the fridge.

I also got fixed my camera lens, which I broke on the day I took this.  The only problem with it was that I broke two little plastic “teeth” off the lens mount (the part that connects to the camera body) when I dropped it on the floor.  It looked like an easy fix, but when I sent it to Canon they quoted me $100 for the repair.  Looking around online I found one place selling the little plastic piece I needed.  Six screws and $20 (shipped) later my lens was like new.  So I guess the moral is, if it seems like you could fix it yourself, you probably can.

My Pioneers theme: ccFlickr

Friday, April 11th, 2008

The Settlers of Catan is a sweet, nerdy, hex-based strategy game. Pioneers is a free software implementation of ‘Settlers’ — some co-workers and I have taken to playing it in the SFLC conference room (and over the tubes) after hours, typically with scotch and pizza. It’s great, you should do it.

They say that every contribution to a free software project begins with one developer’s itch (to see a new feature implemented, a bug fixed, etc.), and the graphical themes (e.g.) that shipped with v.0.11.3 of Pioneers made my brain itch something fierce. So I made a new one. ccFlickr, as the name suggests, is cobbled together from Creative Commons-licensed images harvested from Flickr. Here is a screenshot:

The ccFlickr theme

Download ccFlickr

To install, just place the ccFlickr directory in the directory with all of your other themes. In Ubuntu Linux, this is: /usr/share/games/pioneers/themes/

It’s a first effort, but I’m happy with the result. The one problem I’ve noticed is that, because I made tiles with the exact dimensions of a hex (rather than making smaller images to tile), space sometimes shows up between tiles upon resizing the window. Not sure whether this is an issue with the scaling algorithm, could be fixed by making the tiles rectangles (the space is usually on the diagonal), or if it’s unavoidable.

All of the images I used to make the theme are licensed CC BY-SA (Attribution-Share Alike), so that they can be distributed with the GPL-licensed program. Some images were originally (or still are) licensed CC BY-NC-SA on Flickr. In each of these cases I requested a BY-SA license to the images, and the authors were kind enough to grant one, either by changing the public license on Flickr or by simply giving me a one-off grant of permissions. Here are the images: