The main challenge of tagging is the usability: tags are usually used for navigation, but they are subject to updating at any time. Therefore, tags needs to switch back and forth in display mode and edit mode in a non-intrusive way. Dojo’s dijit.InlineEditBox seems a good candidate for this purpose.

I failed to declare a dijit widget inside the HTML file, maybe the mechanism of dojo.parser prevents me to do so? So I went back to a local copy of dojo-svn and declared FilteredInlineEditBox in dijit namespace:

dojo.provide("dijit.FilteredInlineEditBox");
dojo.require("dijit.InlineEditBox");

dojo.declare("dijit.FilteredInlineEditBox",
        dijit.InlineEditBox,
        {
        postMixInProperties: function() {
                this.inherited(‘postMixInProperties’, arguments);
                this.disabled = true;
        },

        setValue: function(val) {
                this.value = this.filterIn(val);
                this.displayNode.innerHTML = dojo.trim(val) || this.noValueIndicator;
        },

        filterIn: function(val) {
                return val.replace(/<[^>]+>/g, );
        },
});

No extra functionalities added, the inherited functions just manipulate the status for different behaviors. First, the dijit widget is disable by default to block any mouse event.

In the client side, the edit control tailgates the FilteredInlineEditBox:

<p>Tags: <span id="tags" dojoType="dijit.FilteredInlineEditBox" editorParams="{lowercase:true, trim:true,}" onChange="updateTags">
                        {{ object.tags|popuptags|safe }}</span>
                        (<a href="javascript:void(0);" id="edit">edit</a>)

and its onclick is hooked to invoke _edit:

dojo.connect(dojo.byId("edit"), ‘onclick’, function() {
                dijit.byId("tags")._edit();
        });

Notice that _edit never references/modifies disabled, so when the FilteredInlineEditBox exits edit mode, it is still disabled. This is the exact behavior we ask for!

A xhrPost request is used to update the tags asynchronously when onChange is invoked:

def tag_update(request):
        newTag = "none";
        book = Book.objects.get(isbn=request["isbn"])
        if book:
                book.tags = request["tags"]
                book.save()
                tags = [ x for x in re.split("\W+", request["tags"]) if x ]
                newTag = " ".join(['<a href="/bookshelf/tags/%s">%s</a>' % (t, t) for t in tags ])
        return HttpResponse(newTag)

Now in our hack of setValue, the displayNode is still rendered as HTML links, but all the HTML elements are filtered by filterIn, so only the raw text is passed to value, which is used to construct the edit widget later. Therefore, the tags are displayed to users as HTML links, but modified as raw text.

Share and Enjoy:
  • Print this article!
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks

2 Comments to “Learning Django by Example(8) Tag it in place”

  1. ngomaNo Gravatar | February 11th, 2008 at 1:45 pm

    fyi, The tags for this post seemed to have all joined up into one word. Nice post btw.

  2. Getting Started With… | Resource Pile | July 16th, 2008 at 1:19 pm

    [...] Django is an open source web application framework, written in Python, which loosely follows the model-view-controller design pattern. Writing You First Django App Web Monkey’s Getting Started with Django Kunxi.org’s Learning Django by Example(Part 1, 2, 3, 4, 5, 6, 7, 8) [...]

Leave a Comment

This site is using OpenAvatar based on