| 1 | # -*- coding: utf-8 -*-
|
|---|
| 2 |
|
|---|
| 3 | # truncate.py
|
|---|
| 4 | # Copyright © 2009 Paul Schreiber
|
|---|
| 5 | # paulschreiber at gmail dot com
|
|---|
| 6 | # http://paulschreiber.com/
|
|---|
| 7 | # Released under a Creative Commons Attribution-Share Alike 3.0 United States License
|
|---|
| 8 | # http://creativecommons.org/licenses/by-sa/3.0/us/
|
|---|
| 9 | #
|
|---|
| 10 |
|
|---|
| 11 | from django import template
|
|---|
| 12 | from django.template.defaultfilters import stringfilter
|
|---|
| 13 |
|
|---|
| 14 | register = template.Library()
|
|---|
| 15 |
|
|---|
| 16 | @register.filter(name='truncate_head')
|
|---|
| 17 | def truncate_head(value, character_count, ellipsis=True):
|
|---|
| 18 | if value == None:
|
|---|
| 19 | return ""
|
|---|
| 20 |
|
|---|
| 21 | try:
|
|---|
| 22 | length = int(character_count)
|
|---|
| 23 | except ValueError: # Invalid literal for int().
|
|---|
| 24 | return value # Fail silently.
|
|---|
| 25 |
|
|---|
| 26 | if len(value) < length:
|
|---|
| 27 | return value
|
|---|
| 28 |
|
|---|
| 29 | # if we're already on a word boundary, done
|
|---|
| 30 | if value[-(length+1)] == " ":
|
|---|
| 31 | result = value[-length:].strip()
|
|---|
| 32 | else:
|
|---|
| 33 | original_length = len(value)
|
|---|
| 34 | delta = (original_length-length)
|
|---|
| 35 | first_space = value.find(" ", delta, original_length)
|
|---|
| 36 |
|
|---|
| 37 | if first_space == -1:
|
|---|
| 38 | length = delta
|
|---|
| 39 | elif first_space > length:
|
|---|
| 40 | length = first_space
|
|---|
| 41 |
|
|---|
| 42 | result = value[length:].strip()
|
|---|
| 43 |
|
|---|
| 44 | if ellipsis:
|
|---|
| 45 | return u"…" + result
|
|---|
| 46 | else:
|
|---|
| 47 | return result
|
|---|
| 48 |
|
|---|
| 49 | @register.filter(name='truncate_tail')
|
|---|
| 50 | def truncate_tail(value, character_count, ellipsis=True):
|
|---|
| 51 | if value == None:
|
|---|
| 52 | return ""
|
|---|
| 53 |
|
|---|
| 54 | try:
|
|---|
| 55 | length = int(character_count)
|
|---|
| 56 | except ValueError: # Invalid literal for int().
|
|---|
| 57 | return value # Fail silently.
|
|---|
| 58 |
|
|---|
| 59 | if len(value) < length:
|
|---|
| 60 | return value
|
|---|
| 61 |
|
|---|
| 62 | # if we're already on a word boundary, done
|
|---|
| 63 | if value[length] == " ":
|
|---|
| 64 | result = value[:length].strip()
|
|---|
| 65 | else:
|
|---|
| 66 | last_space = value.rfind(" ", 0, length)
|
|---|
| 67 | if last_space != -1 and last_space <= length:
|
|---|
| 68 | length = last_space
|
|---|
| 69 |
|
|---|
| 70 | result = value[:length].strip()
|
|---|
| 71 |
|
|---|
| 72 | if ellipsis:
|
|---|
| 73 | return result + u"…"
|
|---|
| 74 | else:
|
|---|
| 75 | return result
|
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 | @register.filter(name='truncate_middle')
|
|---|
| 79 | def truncate_middle(value, character_count):
|
|---|
| 80 | if value == None:
|
|---|
| 81 | return ""
|
|---|
| 82 |
|
|---|
| 83 | try:
|
|---|
| 84 | length = int(character_count)
|
|---|
| 85 | except ValueError: # Invalid literal for int().
|
|---|
| 86 | return value # Fail silently.
|
|---|
| 87 |
|
|---|
| 88 | if len(value) < length:
|
|---|
| 89 | return value
|
|---|
| 90 |
|
|---|
| 91 | half_size = length / 2
|
|---|
| 92 | first_half = truncate_tail(value, half_size, False)
|
|---|
| 93 | last_half = truncate_head(value, half_size, False)
|
|---|
| 94 |
|
|---|
| 95 | return u"%s…%s" % (first_half, last_half)
|
|---|
| 96 |
|
|---|
| 97 | @register.filter(name='truncatechars')
|
|---|
| 98 | def truncatechars(value, character_count, truncate_type='tail'):
|
|---|
| 99 | """
|
|---|
| 100 | truncatechars(value, character_count, truncate_type='tail')
|
|---|
| 101 |
|
|---|
| 102 | Returns a copy of the string containg only character_counr characters. Try to break on word boundaries.
|
|---|
| 103 |
|
|---|
| 104 | Arguments: Number of characters to truncate after, truncation type (tail/head/middle).
|
|---|
| 105 | """
|
|---|
| 106 |
|
|---|
| 107 | if truncate_type not in ["head", "tail", "middle"]:
|
|---|
| 108 | raise ValueError
|
|---|
| 109 |
|
|---|
| 110 | if value == None:
|
|---|
| 111 | return ""
|
|---|
| 112 |
|
|---|
| 113 | try:
|
|---|
| 114 | length = int(character_count)
|
|---|
| 115 | except ValueError: # Invalid literal for int().
|
|---|
| 116 | return value # Fail silently.
|
|---|
| 117 |
|
|---|
| 118 | if len(value) < length:
|
|---|
| 119 | return value
|
|---|
| 120 |
|
|---|
| 121 | if truncate_type == "tail":
|
|---|
| 122 | return truncate_tail(value, character_count)
|
|---|
| 123 |
|
|---|
| 124 | elif truncate_type == "head":
|
|---|
| 125 | return truncate_head(value, character_count)
|
|---|
| 126 |
|
|---|
| 127 | elif truncate_type == "middle":
|
|---|
| 128 | return truncate_middle(value, character_count)
|
|---|
| 129 |
|
|---|
| 130 |
|
|---|
| 131 | truncatechars.is_safe = True
|
|---|
| 132 | truncate_head.is_safe = True
|
|---|
| 133 | truncate_tail.is_safe = True
|
|---|
| 134 | truncate_middle.is_safe = True
|
|---|
| 135 |
|
|---|