changeset 128:48621ba5c385

Fixing #36, Smilify doesn't work when a smiley appears first before other text. Refactored the smiley system to produce markdown as well as HTML.
author Brian Neal <bgneal@gmail.com>
date Fri, 20 Nov 2009 01:43:32 +0000
parents 2d299909e074
children 70926d0d10b7
files gpp/bio/models.py gpp/comments/models.py gpp/core/markup.py gpp/downloads/models.py gpp/forums/models.py gpp/gcalendar/models.py gpp/messages/models.py gpp/smiley/__init__.py gpp/smiley/models.py gpp/smiley/templatetags/smiley_tags.py gpp/templates/membermap/markdown.html gpp/templates/shoutbox/render_shout.html gpp/templates/shoutbox/shout.html gpp/templates/shoutbox/shout_detail.html gpp/templates/shoutbox/shoutbox.html
diffstat 15 files changed, 119 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/bio/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/bio/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -10,8 +10,7 @@
 from django.conf import settings
 from django.core.cache import cache
 
-from core.markup import Markdown
-from smiley import Smilify
+from core.markup import SiteMarkup
 
 
 def avatar_file_path_for_user(username, filename):
@@ -48,9 +47,8 @@
         ordering = ('user__username', )
 
     def save(self, *args, **kwargs):
-        md = Markdown()
-        sm = Smilify()
-        self.profile_html = sm.convert(md.convert(self.profile_text))
-        self.signature_html = sm.convert(md.convert(self.signature))
+        sm = SiteMarkup()
+        self.profile_html = sm.convert(self.profile_text)
+        self.signature_html = sm.convert(self.signature)
         super(UserProfile, self).save(*args, **kwargs)
         cache.delete('avatar_' + self.user.username)
--- a/gpp/comments/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/comments/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -8,8 +8,7 @@
 from django.contrib.auth.models import User
 from django.core import urlresolvers
 
-from core.markup import markdown
-from smiley import smilify
+from core.markup import site_markup
 
 
 COMMENT_MAX_LENGTH = getattr(settings, 'COMMENT_MAX_LENGTH', 3000)
@@ -53,7 +52,7 @@
         return u'%s: %s...' % (self.user.username, self.comment[:50])
 
     def save(self, force_insert=False, force_update=False):
-        self.html = smilify(markdown(self.comment))
+        self.html = site_markup(self.comment)
         super(Comment, self).save(force_insert, force_update)
 
     def get_absolute_url(self):
--- a/gpp/core/markup.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/core/markup.py	Fri Nov 20 01:43:32 2009 +0000
@@ -1,17 +1,19 @@
 """
-This is a thin wrapper around the Markdown class which deals with the
-differences in Markdown versions on the production and development server.
-This code was inspired by the code in 
-django/contrib/markup/templatetags/markup.py.
-Currently, we only have to worry about Markdown 1.6b and 2.0.
+Markup related utitlities useful for the entire project.
 """
 import markdown as _markdown
 from django.utils.encoding import force_unicode
 
-from smiley.utils import smilify
+from smiley import Smilify
 
 class Markdown(object):
-
+    """
+    This is a thin wrapper around the Markdown class which deals with the
+    differences in Markdown versions on the production and development server.
+    This code was inspired by the code in 
+    django/contrib/markup/templatetags/markup.py.
+    Currently, we only have to worry about Markdown 1.6b and 2.0.
+    """
     def __init__(self, safe_mode='escape'):
         # Unicode support only in markdown v1.7 or above. Version_info
         # exists only in markdown v1.6.2rc-2 or above.
@@ -26,5 +28,29 @@
 
 
 def markdown(s):
+    """
+    A convenience function for one-off markdown jobs.
+    """
     md = Markdown()
     return md.convert(s)
+
+
+class SiteMarkup(object):
+    """
+    This class provides site markup by combining markdown and
+    our own smiley markup.
+    """
+    def __init__(self):
+        self.md = Markdown()
+        self.smiley = Smilify()
+
+    def convert(self, s):
+        return self.md.convert(self.smiley.markdown(s))
+
+
+def site_markup(s):
+    """
+    Convenience function for one-off site markup jobs.
+    """
+    sm = SiteMarkup()
+    return sm.convert(s)
--- a/gpp/downloads/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/downloads/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -8,8 +8,7 @@
 from django.contrib.auth.models import User
 from django.template.defaultfilters import filesizeformat
 
-from core.markup import markdown
-from smiley import smilify
+from core.markup import site_markup
 
 
 class Category(models.Model):
@@ -74,7 +73,7 @@
         return ('downloads-details', [str(self.id)])
 
     def save(self, force_insert=False, force_update=False):
-        self.html = smilify(markdown(self.description))
+        self.html = site_markup(self.description)
         super(Download, self).save(force_insert, force_update)
 
     def vote(self, vote_value):
--- a/gpp/forums/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/forums/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -6,8 +6,8 @@
 from django.db import models
 from django.db.models import Q
 from django.contrib.auth.models import User, Group
-from core.markup import markdown
-from smiley import smilify
+
+from core.markup import site_markup
 
 
 POST_EDIT_DELTA = datetime.timedelta(seconds=3)
@@ -252,7 +252,7 @@
         return self.summary()
 
     def save(self, *args, **kwargs):
-        self.html = smilify(markdown(self.body))
+        self.html = site_markup(self.body)
         super(Post, self).save(*args, **kwargs)
 
     def delete(self, *args, **kwargs):
--- a/gpp/gcalendar/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/gcalendar/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -5,8 +5,7 @@
 from django.db.models import Q
 from django.contrib.auth.models import User
 
-from core.markup import markdown
-from smiley import smilify
+from core.markup import site_markup
 
 
 class PendingEventManager(models.Manager):
@@ -92,7 +91,7 @@
         ordering = ('-date_submitted', )
 
     def save(self, *args, **kwargs):
-        self.html = smilify(markdown(self.description))
+        self.html = site_markup(self.description)
         super(Event, self).save(*args, **kwargs)
 
     def needs_approval(self):
--- a/gpp/messages/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/messages/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -1,11 +1,12 @@
 """Models for the messages application."""
 
 import datetime
+
 from django.db import models
 from django.db.models import Q
 from django.contrib.auth.models import User
-from core.markup import markdown
-from smiley import smilify
+
+from core.markup import site_markup
 
 
 class MessageManager(models.Manager):
@@ -63,7 +64,7 @@
     def save(self, force_insert = False, force_update = False):
         if not self.id:
             self.send_date = datetime.datetime.now()
-        self.html = smilify(markdown(self.message))
+        self.html = site_markup(self.message)
         super(Message, self).save(force_insert, force_update)
 
     @models.permalink
--- a/gpp/smiley/__init__.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/smiley/__init__.py	Fri Nov 20 01:43:32 2009 +0000
@@ -11,12 +11,21 @@
 
 class Smilify(object):
     """
-    A class to "smilify" text by replacing text with HTML img tags of smilies.
+    A class to "smilify" text by replacing text with either HTML img tags 
+    or markdown syntax for smiley images.
     """
+    HTML = 0
+    MARKDOWN = 1
+
     def __init__(self):
         self.map = Smiley.objects.get_smiley_map()
 
-    def convert(self, value, autoescape=False):
+    def _convert(self, value, rep_index, autoescape=False):
+        """
+        Converts and returns the supplied text with either the
+        HTML or markdown version of the smileys according to the
+        output parameter.
+        """
         if not autoescape or isinstance(value, SafeData):
             esc = lambda x: x
         else:
@@ -25,17 +34,39 @@
         words = value.split()
         for i, word in enumerate(words):
             if word in self.map:
-                words[i] = self.map[word]
+                words[i] = self.map[word][rep_index]
             else:
                 words[i] = esc(words[i])
         return u' '.join(words)
+
+    def html(self, value, autoescape=False):
+        """
+        Converts the supplied text by replacing the smiley codes with
+        HTML img tags.
+        """
+        return self._convert(value, self.HTML, autoescape=autoescape)
+
+    def markdown(self, value, autoescape=False):
+        """
+        Converts the supplied text by replacing the smiley codes with
+        markdown image syntax.
+        """
+        return self._convert(value, self.MARKDOWN, autoescape=autoescape)
         
 
-def smilify(value, autoescape=False):
+def smilify_html(value, autoescape=False):
     """
     A convenience function to "smilify" text by replacing text with HTML
     img tags of smilies.
     """
     s = Smilify()
-    return s.convert(value, autoescape)
+    return s.html(value, autoescape=autoescape)
 
+
+def smilify_markdown(value, autoescape=False):
+    """
+    A convenience function to "smilify" text by replacing text with 
+    markdown syntax for the images of smilies.
+    """
+    s = Smilify()
+    return s.markdown(value, autoescape=autoescape)
--- a/gpp/smiley/models.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/smiley/models.py	Fri Nov 20 01:43:32 2009 +0000
@@ -4,17 +4,23 @@
 from django.db import models
 from django.core.cache import cache
 
-CACHE_TIMEOUT = 60 * 5      # seconds
+CACHE_TIMEOUT = 60 * 60      # seconds
 
 
 class SmileyManager(models.Manager):
 
     def get_smiley_map(self):
+        """
+        Returns a dictionary of 2-tuples, indexed by smiley codes.
+        Element 0 of the tuple is the HTML representation of the smiley,
+        and element 1 is the markdown version.
+        The dictionary is cached.
+        """
         map = cache.get('smiley_map')
         if map:
             return map
 
-        map = dict((s.code, s.html()) for s in self.all())
+        map = dict((s.code, (s.html(), s.markdown())) for s in self.all())
         cache.set('smiley_map', map, CACHE_TIMEOUT)
         return map
 
@@ -48,9 +54,16 @@
         return self.image.url
 
     def html(self):
+        """Returns a HTML img tag representation of the smiley."""
         if self.image:
             return (u'<img src="%s" alt="%s" title="%s" />' %
                     (self.get_absolute_url(), self.title, self.title))
         return u''
     html.allow_tags = True
 
+    def markdown(self):
+        """Returns a markdown representation of the smiley."""
+        if self.image:
+            return (u'![%s](%s "%s")' % 
+                    (self.title, self.get_absolute_url(), self.title))
+        return u''
--- a/gpp/smiley/templatetags/smiley_tags.py	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/smiley/templatetags/smiley_tags.py	Fri Nov 20 01:43:32 2009 +0000
@@ -12,11 +12,20 @@
 
 @register.filter
 @stringfilter
-def smilify(value, autoescape=False):
+def smiley_html(value, autoescape=False):
     """A filter to "smilify" text by replacing text with HTML img tags of smilies."""
-    from smiley import smilify
-    return mark_safe(smilify(value, autoescape))
-smilify.needs_autoescape = True
+    from smiley import smilify_html
+    return mark_safe(smilify_html(value, autoescape=autoescape))
+smiley_html.needs_autoescape = True
+
+
+@register.filter
+@stringfilter
+def smiley_markdown(value, autoescape=False):
+    """A filter to "smilify" text by replacing text with HTML img tags of smilies."""
+    from smiley import smilify_markdown
+    return mark_safe(smilify_markdown(value, autoescape=autoescape))
+smiley_markdown.needs_autoescape = True
 
 
 @register.inclusion_tag('smiley/smiley_farm.html')
--- a/gpp/templates/membermap/markdown.html	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/templates/membermap/markdown.html	Fri Nov 20 01:43:32 2009 +0000
@@ -1,4 +1,4 @@
 {% load markup %}
 {% load smiley_tags %}
 {% load avatar_tags %}
-{% avatar entry.user "left" %}<a href="{% url bio-view_profile username=entry.user.username %}">{{ entry.user.username }}</a>:<br />{{ entry.message|markdown:"safe"|smilify }}
+{% avatar entry.user "left" %}<a href="{% url bio-view_profile username=entry.user.username %}">{{ entry.user.username }}</a>:<br />{{ entry.message|smiley_markdown|markdown:"safe" }}
--- a/gpp/templates/shoutbox/render_shout.html	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/templates/shoutbox/render_shout.html	Fri Nov 20 01:43:32 2009 +0000
@@ -1,2 +1,2 @@
 {% load smiley_tags %}
-{{ shout.shout|smilify|urlize }}
+{{ shout.shout|smiley_html|urlize }}
--- a/gpp/templates/shoutbox/shout.html	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/templates/shoutbox/shout.html	Fri Nov 20 01:43:32 2009 +0000
@@ -1,6 +1,6 @@
 {% load smiley_tags %}
 <p style="display:none;">
 <span class="shoutbox-user">{{ shout.user.username }}:</span>
-<span class="shoutbox-shout">{{ shout.shout|smilify|urlizetrunc:15 }}</span>
+<span class="shoutbox-shout">{{ shout.shout|smiley_html|urlizetrunc:15 }}</span>
 <span class="shoutbox-date">{{ shout.shout_date|date:"D M d Y H:i:s" }}</span>
 </p>
--- a/gpp/templates/shoutbox/shout_detail.html	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/templates/shoutbox/shout_detail.html	Fri Nov 20 01:43:32 2009 +0000
@@ -6,7 +6,7 @@
 <a href="{% url bio-view_profile username=shout.user.username %}">{{ shout.user.username }}</a>
 </th>
 <td>
-<div {% ifequal user shout.user %}class="edit" id="shout-{{ shout.id }}"{% endifequal %}>{{ shout.shout|smilify|urlize }}</div>
+<div {% ifequal user shout.user %}class="edit" id="shout-{{ shout.id }}"{% endifequal %}>{{ shout.shout|smiley_html|urlize }}</div>
 </div>
 <br />
 <span class="date">{{ shout.shout_date|date:"D M d Y H:i:s" }}</span><br />
--- a/gpp/templates/shoutbox/shoutbox.html	Mon Nov 16 01:00:28 2009 +0000
+++ b/gpp/templates/shoutbox/shoutbox.html	Fri Nov 20 01:43:32 2009 +0000
@@ -6,7 +6,7 @@
    {% for shout in shouts %}
       <p>
       <span class="shoutbox-user">{{ shout.user.username }}:</span>
-      <span class="shoutbox-shout">{{ shout.shout|smilify|urlizetrunc:15 }}</span>
+      <span class="shoutbox-shout">{{ shout.shout|smiley_html|urlizetrunc:15 }}</span>
       <span class="shoutbox-date">{{ shout.shout_date|date:"D M d Y H:i:s" }}</span>
       </p>
    {% endfor %}