<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Death of a Gremmie &#187; smilies</title>
	<atom:link href="http://deathofagremmie.com/tag/smilies/feed/" rel="self" type="application/rss+xml" />
	<link>http://deathofagremmie.com</link>
	<description>by Brian Neal</description>
	<lastBuildDate>Wed, 14 Jul 2010 02:31:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Anatomy of a Shoutbox; Part 4 &#8211; Smilies!</title>
		<link>http://deathofagremmie.com/2008/12/14/anatomy-of-a-shoutbox-part-4-smilies/</link>
		<comments>http://deathofagremmie.com/2008/12/14/anatomy-of-a-shoutbox-part-4-smilies/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 19:43:15 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[SG101 2.0]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[sg101]]></category>
		<category><![CDATA[shoutbox]]></category>
		<category><![CDATA[smilies]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=79</guid>
		<description><![CDATA[I&#8217;ve been making some great progress on the shoutbox. I&#8217;ve added smilies and I used a jQuery plugin to get the edit-in-place working. It&#8217;s awesome! Meanwhile, while it is fresh in my mind, I&#8217;ll post about the smilies here. In case you missed the earlier parts, here they are: part 1, part 2, part 3. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been making some great progress on the shoutbox. I&#8217;ve added smilies and I used a jQuery plugin to get the edit-in-place working. It&#8217;s awesome! Meanwhile, while it is fresh in my mind, I&#8217;ll post about the smilies here.</p>
<p>In case you missed the earlier parts, here they are:  <a href="http://deathofagremmie.com/2008/12/02/anatomy-of-a-shoutbox-part-1-requirements/">part 1</a>, <a href="http://deathofagremmie.com/2008/12/07/anatomy-of-a-shoutbox-part-2-model-and-admin/">part 2</a>, <a href="http://deathofagremmie.com/2008/12/08/anatomy-of-a-shoutbox-part-3-view-template/">part 3</a>.</p>
<p>One of the &#8220;fun&#8221; features of the shoutbox is the smilies, or emoticons. In a nutshell, certain character sequences are translated into small images in the &#8220;shout&#8221; text. Furthermore, all of the images are displayed below the shoutbox, and by clicking on them they get added to the shout the user is typing via some simple javascript.</p>
<p>I can see myself using this smiley function in lots of places: shoutbox, user comments, photo of the day, forums, etc. So I created a new application for it, separate from the shoutbox application.</p>
<p>I read up on django&#8217;s custom filter documentation, and spent a fair amount of time scratching my head over the <a href="http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#filters-and-auto-escaping">auto-escaping feature</a>. It suddenly occured to me that what I need is similar to the django <a href="http://docs.djangoproject.com/en/dev/ref/templates/builtins/#urlize">urlize filter</a>: go through some text and replace certain phrases with HTML. In the urlize case this is an &lt;a&gt; tag. In my case this is an &lt;img&gt; tag. I then studied the urlize filter source to steer me. Mine turned out a bit simpler as you will see below.</p>
<p>First let&#8217;s start with the model. I wanted to be able to easily edit and add smilies via the admin interface. The legacy shoutbox allowed many &#8220;phrases&#8221; to map to a single smiley, but it did this in a redundant way. I decided to keep things simple and only allow one phrase per smiley. Part of this was driven by the fact that if the user clicks on a smiley I need to add the phrase to the text they are typing. If there are multiple phrases, which do I use? I suppose I could have picked the first one, but this was going against my &#8220;let&#8217;s keep this simple for now&#8221; philosophy. Here is the model I came up with:</p>
<p><span id="more-79"></span></p>
<pre class="brush: python">class Smiley(models.Model):
    image = models.ImageField(upload_to=&#039;smiley/images/&#039;)
    title = models.CharField(max_length=32)
    code = models.CharField(max_length=32)

    objects = SmileyManager()

    class Meta:
        verbose_name_plural = &#039;Smilies&#039;
        ordering = (&#039;title&#039;, )

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return self.image.url

    def html(self):
        if self.image:
            return u&#039;&lt;img src=&quot;%s&quot; alt=&quot;%s&quot; title=&quot;%s&quot; /&gt;&#039; % \
                    (self.get_absolute_url(), self.title, self.title)
        return u&#039;&#039;
    html.allow_tags = True
</pre>
<p>This is pretty straightforward. I&#8217;ll explain the custom manager in a bit. I wanted to be able to show the smiley image in the admin section, so I added a html() member function to the Smiley class. This would be useful in templates also. In order to get the HTML to display correctly in the admin, I needed to add an &#8220;allow_tags&#8221; attribute set to True to the html() function. I can then use the html() function in the admin class in my admin.py file:</p>
<pre class="brush: python">from django.contrib import admin
from smiley.models import Smiley

class SmileyAdmin(admin.ModelAdmin):
    list_display = (&#039;title&#039;, &#039;code&#039;, &#039;html&#039;)

admin.site.register(Smiley, SmileyAdmin)</pre>
<p>And with just that little bit of code I now have a nice admin interface to add smilies.</p>
<div id="attachment_84" class="wp-caption alignnone" style="width: 160px"><a href="http://deathofagremmie.com/wp-content/uploads/2008/12/admin.png"><img class="size-thumbnail wp-image-84" title="Admin View of Smilies" src="http://deathofagremmie.com/wp-content/uploads/2008/12/admin-150x150.png" alt="Admin View of Smilies" width="150" height="150" /></a><p class="wp-caption-text">Admin View of Smilies</p></div>
<p>I then turned my attention to creating a custom filter for &#8220;smilifying&#8221; text. Again, I studied the urlize filter to see what was being done there (splitting the text into words), but steered my code towards the example in the documentation on how to handle auto-escaping. I realized that I could be hitting the database a lot to read the smiley definitions trying to smilify text, so I decided to cache the smiley information. A convenient way to do this was to add a custom Smiley model manager. I knew I needed a dictionary that mapped smiley code phrases to &lt;img&gt; HTML. And I probably would need to cache the smiley objects themselves. I handled this in a custom model manager (in models.py):</p>
<pre class="brush: python">class SmileyManager(models.Manager):
    smiley_map = None
    smilies = None

    def get_smiley_map(self):
        if self.smiley_map is None:
            smilies = self.all()
            self.smiley_map = {}
            for s in smilies:
                self.smiley_map[s.code] = s.html()
        return self.smiley_map

    def get_smilies(self):
        if self.smilies is None:
            self.smilies = self.all()
        return self.smilies

    def clear_cache(self):
        self.smiley_map = None
        self.smilies = None
</pre>
<p>The get_smiley_map() and get_smilies() use caching techniques to minimize database hits. I added a clear_cache() function to force a re-read of the database. I envision that if I ever need to add or delete a smiley from the admin interface I will need to add a custom admin view that calls clear_cache(). We&#8217;ll leave that as a hook for now and cross that bridge later. Now my filter code can simply call the Smiley objects manager to get the &#8220;smiley map&#8221;.</p>
<p>Here is my new filter called, of course, &#8220;smilify&#8221;. I put this in the templatetags directory in a file called smiley_tags.py:</p>
<pre class="brush: python">import re
from django import template
from django.template.defaultfilters import stringfilter
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe

from smiley.models import Smiley

register = template.Library()

word_split_re = re.compile(r&#039;(\s+)&#039;)

@register.filter
@stringfilter
def smilify(value, autoescape=False):
    &quot;&quot;&quot;A filter to &quot;smilify&quot; text by replacing text with HTML img tags of smilies.&quot;&quot;&quot;
    if autoescape:
        esc = conditional_escape
    else:
        esc = lambda x: x

    smiley_map = Smiley.objects.get_smiley_map()

    words = word_split_re.split(value)
    for i, word in enumerate(words):
        if word in smiley_map:
            words[i] = smiley_map[word]
        else:
            words[i] = esc(words[i])
    return mark_safe(u&#039;&#039;.join(words))
smilify.needs_autoescape = True
</pre>
<p>The basic idea is to split the text into words. If a word is in our smiley map, substitute it with the corresponding &lt;img&gt; tag. Otherwise we need to escape the word. At the end we join the words together and mark the resulting string safe.</p>
<p>I then updated my shoutbox template to use this new filter and voila we had smilies!</p>
<div id="attachment_85" class="wp-caption alignnone" style="width: 253px"><a href="http://deathofagremmie.com/wp-content/uploads/2008/12/shoutbox1.png"><img class="size-full wp-image-85" title="Smilies!" src="http://deathofagremmie.com/wp-content/uploads/2008/12/shoutbox1.png" alt="Smilies" width="243" height="330" /></a><p class="wp-caption-text">Smilies</p></div>
<p>Finally I needed a way to present all of the smileys to the user. These smilies would be clickable, and doing so would add the code for that smiley to whatever input box the comment or shout would be using. I created an inclusion tag called smiley_farm in my smiley_tags.py file to handle this. It uses the Smiley manager&#8217;s get_smilies functions, which caches the smiley objects:</p>
<pre class="brush: python">@register.inclusion_tag(&#039;smiley/smiley_farm.html&#039;)
def smiley_farm():
    &quot;&quot;&quot;An inclusion tag that displays all of the smilies in clickable form.&quot;&quot;&quot;
    return {&#039;smilies&#039;: Smiley.objects.get_smilies(), }
</pre>
<p>The template smiley_farm.html looks like this:</p>
<pre class="brush: html">&lt;div class=&quot;smiley_farm&quot;&gt;
{% for s in smilies %}
    &lt;img src=&quot;{{ s.image.url }}&quot; alt=&quot;{{ s.code }}&quot; title=&quot;{{ s.title }} {{ s.code }}&quot;
        onclick=&quot;sb_smiley_click(&#039; {{ s.code }} &#039;);&quot; /&gt;
{% endfor %}
&lt;/div&gt;
</pre>
<p>I enclose the smilies in a div so I can easily style them with CSS. In particular I added a cursor: pointer style to the images so that the mouse pointer will indicate to the user that the smilies can be clicked. When you click on a smiley, the sb_smiley_click() javascript function will run, which simply adds the smiley code phrase to an input text with a certain id:</p>
<pre class="brush: javascript">function sb_smiley_click(code)
{
    var txt = document.getElementById(&quot;shoutbox-smiley-input&quot;);
    txt.value += code;
    txt.focus();
}</pre>
<p>As I learn more about jQuery I hope to revisit this code and add the onclick function to the images after the page has loaded.</p>
<p>Finally, I added a bit of javascript to hide the smiley farm until the user clicks a button labeled &#8220;Smilies&#8221; to reveal them to conserve screen real estate. This idea and behavior is copied from the legacy shoutbox.</p>
<div id="attachment_86" class="wp-caption alignnone" style="width: 243px"><a href="http://deathofagremmie.com/wp-content/uploads/2008/12/shoutbox2.png"><img class="size-full wp-image-86" title="Shoutbox with Smiley Farm" src="http://deathofagremmie.com/wp-content/uploads/2008/12/shoutbox2.png" alt="Shoutbox with Smiley Farm" width="233" height="432" /></a><p class="wp-caption-text">Shoutbox with Smiley Farm</p></div>
<p>That was a long post but with these pretty simple pieces in place I now have smilies for the shoutbox and other applications to use!</p>
<p>In the next post I&#8217;ll show how I got the edit-in-place functionality working.</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2008/12/14/anatomy-of-a-shoutbox-part-4-smilies/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
