diff --git a/basic/tools/__init__.py b/basic/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basic/tools/templatetags/__init__.py b/basic/tools/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/basic/tools/templatetags/capture.py b/basic/tools/templatetags/capture.py new file mode 100644 index 0000000..c1fd843 --- /dev/null +++ b/basic/tools/templatetags/capture.py @@ -0,0 +1,24 @@ +from django import template +from django.utils.safestring import mark_safe + +register = template.Library() + +@register.tag +def capture(parser, token): + """{% capture as [foo] %}""" + bits = token.split_contents() + if len(bits) != 3: + raise template.TemplateSyntaxError("'capture' node requires `as (variable name)`.") + nodelist = parser.parse(('endcapture',)) + parser.delete_first_token() + return CaptureNode(nodelist, bits[2]) + +class CaptureNode(template.Node): + def __init__(self, nodelist, varname): + self.nodelist = nodelist + self.varname = varname + + def render(self, context): + output = self.nodelist.render(context) + context[self.varname] = mark_safe(output.strip()) + return '' \ No newline at end of file diff --git a/basic/tools/templatetags/comparison.py b/basic/tools/templatetags/comparison.py new file mode 100644 index 0000000..0ebdc6b --- /dev/null +++ b/basic/tools/templatetags/comparison.py @@ -0,0 +1,88 @@ +from django.template import Library +from django.template.defaultfilters import lower + +register = Library() + +@register.filter +def gt(value, arg): + "Returns a boolean of whether the value is greater than the argument" + try: + return float(value) > float(arg) + except (ValueError,TypeError): + return "" + +@register.filter +def lt(value, arg): + "Returns a boolean of whether the value is less than the argument" + try: + return float(value) < float(arg) + except (ValueError,TypeError): + return "" + +@register.filter +def gte(value, arg): + "Returns a boolean of whether the value is greater than or equal to the argument" + try: + return float(value) >= float(arg) + except (ValueError,TypeError): + return "" + +@register.filter +def lte(value, arg): + "Returns a boolean of whether the value is less than or equal to the argument" + try: + return float(value) <= float(arg) + except (ValueError,TypeError): + return "" + +@register.filter +def is_content_type(obj, arg): + try: + ct = lower(obj._meta.object_name) + return ct == arg + except AttributeError: + return "" + +@register.filter +def is_equal(obj, arg): + "Returns a boolean of whether the value is equal to the argument" + return obj == arg + +@register.filter +def round(obj): + "Returns a number rounded." + try: + return round(obj) + except (ValueError,TypeError): + return "" + +@register.filter +def has(obj, arg): + "Returns a boolean of whether the value is in a list of values or a string" + try: + if arg in obj: + return True + except TypeError: + return "" + return False + + +@register.filter +def is_string(obj): + return isinstance(obj, str) + + +@register.filter +def is_number(obj): + return isinstance(obj, int) + + +@register.filter +def get_vars(obj): + getvars = obj.copy() + if 'page' in obj: + del getvars['page'] + if len(getvars.keys()) > 0: + return "&%s" % getvars.urlencode() + else: + return '' \ No newline at end of file diff --git a/basic/tools/templatetags/stringutils.py b/basic/tools/templatetags/stringutils.py new file mode 100644 index 0000000..c8c5518 --- /dev/null +++ b/basic/tools/templatetags/stringutils.py @@ -0,0 +1,33 @@ +import re + +from django.template import Library +from django.contrib.markup.templatetags.markup import markdown +from django.template.defaultfilters import urlizetrunc +from django.utils.safestring import mark_safe + +register = Library() + + +@register.filter +def twitterize(value): + try: + new_value = re.sub(r'(@)(\w+)', '\g<1>\g<2>', value) + return mark_safe(new_value) + except: + return value + + +@register.filter +def strip(value, arg): + return value.strip(arg) + + +@register.filter +def smarty(value): + from smartypants import smartyPants + return value + + +@register.filter +def format_text(value): + return twitterize(urlizetrunc(markdown(value), 30)) diff --git a/basic/tools/templatetags/thumbnail.py b/basic/tools/templatetags/thumbnail.py new file mode 100644 index 0000000..b795cd2 --- /dev/null +++ b/basic/tools/templatetags/thumbnail.py @@ -0,0 +1,129 @@ +from django import template +from django.conf import settings +register = template.Library() + + +# Useful functions +def _get_path_from_url(url, root=settings.MEDIA_ROOT, url_root=settings.MEDIA_URL): + """ make filesystem path from url """ + import os + if url.startswith(url_root): + url = url[len(url_root):] # strip media root url + return settings.MEDIA_ROOT + url + + +# Tags +@register.filter +def thumbnail(url, size='200x200'): + """ + Given a URL (local or remote) to an image, creates a thumbnailed version of the image, saving + it locally and then returning the URL to the new, smaller version. If the argument passed is a + single integer, like "200", will output a version of the image no larger than 200px wide. If the + argument passed is two integers, like, "200x300", will output a cropped version of the image that + is exactly 200px wide by 300px tall. + + Examples: + + {{ story.leadphoto.url|thumbnail:"200" }} + {{ story.leadphoto.url|thumbnail:"300x150" }} + + """ + import Image + import os + import urllib + + original_url = url + + # First, find the image, either via local file path or http. + filename = os.path.join(settings.MEDIA_ROOT, url) + + if url.startswith('http://') or url.startswith('https://'): + # If it's a remote image, download it and save it locally. This expects a + # directory called downloaded/ in your MEDIA_ROOT + download_filename = url.rsplit('/', 1)[1] # Filename of image + full_image_path = '%sdownloaded/%s' % (settings.MEDIA_ROOT, download_filename) # Local filesystem path where image should be saved + local_image_url = '%sdownloaded/%s' % (settings.MEDIA_URL, download_filename) # URL to local copy of image + + if not os.path.exists(full_image_path): + unsized_image = urllib.urlretrieve(url) # Fetch original image + unsized_image = Image.open(unsized_image[0]) # Load the fetched image + local_image = unsized_image.save(full_image_path) # Save the resized image locally + + url = local_image_url + remote_image = True + else: + # If it's a local image, note it and move on. + remote_image = False + + # Define the thumbnail's filename, file path, and URL. + try: + basename, format = url.rsplit('.', 1) + except ValueError: + return os.path.join(settings.MEDIA_URL, url) + thumbnail = basename + '_t' + size + '.' + format + thumbnail_filename = _get_path_from_url(thumbnail) + thumbnail_url = thumbnail + + # Find out if a thumbnail in this size already exists. If so, we'll not remake it. + if not os.path.exists(thumbnail_filename): + # The thumbnail doesn't already exist. Log a message that we are resizing. + + # Open the image. + try: + image = Image.open(_get_path_from_url(url)) + except IOError: + return os.path.join(settings.MEDIA_URL, url) + + # Make a copy of the original image so we can access its attributes, even + # after we've changed some of them. + original_image = image.copy() + + # Find the size of the original image. + original_width = original_image.size[0] + original_height = original_image.size[1] + + # Parse the size argument into integers. + try: + # See if both height and width exist (i.e. "200x100") + desired_width, desired_height = [int(x) for x in size.split('x')] + new_size = (desired_width, desired_height) + # Flag this image for cropping, since we want an explicit width AND height. + crop = True + except ValueError: + # If only one exists ( i.e. "200"), use the value as the desired width. + if size[0] == 'x': + desired_height = int(size[1:]) + new_size = (original_width, desired_height) + crop = False + else: + desired_width = int(size) + new_size = (desired_width, original_height) + crop = False + + # If we are to crop this image, we'll thumbnail it, and then figure out the proper crop area + # Crops are done from the center of the image. + if crop: + if (original_height / (original_width / float(desired_width))) < desired_height: + image.thumbnail((original_width, desired_height), Image.ANTIALIAS) + else: + image.thumbnail((desired_width, original_height), Image.ANTIALIAS) + + if (image.size[0] >= desired_width) and (image.size[1] >= desired_height): + left = (image.size[0] - desired_width) / 2 + top = (image.size[1] - desired_height) / 2 + right = left + desired_width + bottom = top + desired_height + cropped_image = image.crop((left, top, right, bottom)) + image = cropped_image + else: + # If we are not to crop this image, simply thumbnail it down to the desired width. + image.thumbnail(new_size, Image.ANTIALIAS) + + # Finally, save the image. + try: + image.save(thumbnail_filename, image.format, quality=85) + except KeyError: + return '' + + # And return the URL to the new thumbnailed version. + return os.path.join(settings.MEDIA_URL, thumbnail_url) \ No newline at end of file