| 1 | from django import template |
|---|
| 2 | from django.utils.http import urlquote |
|---|
| 3 | from telemeta import models |
|---|
| 4 | from django.core.urlresolvers import reverse |
|---|
| 5 | import telemeta.models.dublincore as dc |
|---|
| 6 | from django.utils import html |
|---|
| 7 | from django import template |
|---|
| 8 | from django.utils.text import capfirst |
|---|
| 9 | from django.utils.translation import ungettext |
|---|
| 10 | from docutils.core import publish_parts |
|---|
| 11 | from django.utils.encoding import smart_str, force_unicode |
|---|
| 12 | from django.utils.safestring import mark_safe |
|---|
| 13 | from django import db |
|---|
| 14 | import re |
|---|
| 15 | import datetime |
|---|
| 16 | from django.conf import settings |
|---|
| 17 | |
|---|
| 18 | register = template.Library() |
|---|
| 19 | |
|---|
| 20 | @register.filter |
|---|
| 21 | def tolist(dict): |
|---|
| 22 | "Converts a simple dict into a list" |
|---|
| 23 | list = [] |
|---|
| 24 | for k, v in dict.iteritems(): |
|---|
| 25 | list.append({'name': k, 'value': v}) |
|---|
| 26 | return list |
|---|
| 27 | |
|---|
| 28 | @register.filter |
|---|
| 29 | def mul(value, arg): |
|---|
| 30 | "Multiply a numeric value" |
|---|
| 31 | return value * arg |
|---|
| 32 | |
|---|
| 33 | class TelemetaVersionNode(template.Node): |
|---|
| 34 | def render(self, context): |
|---|
| 35 | from telemeta import __version__ |
|---|
| 36 | return __version__ |
|---|
| 37 | |
|---|
| 38 | @register.tag |
|---|
| 39 | def telemeta_version(parser, token): |
|---|
| 40 | "Get Telemeta version number" |
|---|
| 41 | return TelemetaVersionNode() |
|---|
| 42 | |
|---|
| 43 | class TelemetaUrlNode(template.Node): |
|---|
| 44 | def render(self, context): |
|---|
| 45 | from telemeta import __url__ |
|---|
| 46 | return __url__ |
|---|
| 47 | |
|---|
| 48 | @register.tag |
|---|
| 49 | def telemeta_url(parser, token): |
|---|
| 50 | "Get Telemeta project homepage URL" |
|---|
| 51 | return TelemetaUrlNode() |
|---|
| 52 | |
|---|
| 53 | _js_escapes = ( |
|---|
| 54 | ('\\', '\\\\'), |
|---|
| 55 | ('"', '\\"'), |
|---|
| 56 | ("'", "\\'"), |
|---|
| 57 | ('\n', '\\n'), |
|---|
| 58 | ('\r', '\\r'), |
|---|
| 59 | ('\b', '\\b'), |
|---|
| 60 | ('\f', '\\f'), |
|---|
| 61 | ('\t', '\\t'), |
|---|
| 62 | ('\v', '\\v'), |
|---|
| 63 | ('</', '<\\/'), |
|---|
| 64 | ) |
|---|
| 65 | @register.filter |
|---|
| 66 | def escapejs(value): |
|---|
| 67 | """Backslash-escapes characters for use in JavaScript strings.""" |
|---|
| 68 | for bad, good in _js_escapes: |
|---|
| 69 | value = value.replace(bad, good) |
|---|
| 70 | return value |
|---|
| 71 | |
|---|
| 72 | @register.filter |
|---|
| 73 | def build_query_string(vars): |
|---|
| 74 | """Build an HTTP query string out of a dict""" |
|---|
| 75 | if type(vars) == dict: |
|---|
| 76 | import urllib |
|---|
| 77 | args = [] |
|---|
| 78 | for k, v in vars.iteritems(): |
|---|
| 79 | if isinstance(v, db.models.Model): |
|---|
| 80 | v = v.pk |
|---|
| 81 | elif not isinstance(v, basestring): |
|---|
| 82 | v = unicode(v) |
|---|
| 83 | args.append(urlquote(k) + '=' + urlquote(v)) |
|---|
| 84 | |
|---|
| 85 | return "&".join(args) |
|---|
| 86 | return '' |
|---|
| 87 | |
|---|
| 88 | @register.filter |
|---|
| 89 | def code_or_id(resource): |
|---|
| 90 | if resource.code: |
|---|
| 91 | return resource.code |
|---|
| 92 | else: |
|---|
| 93 | return resource.id |
|---|
| 94 | |
|---|
| 95 | @register.filter |
|---|
| 96 | def is_item(resource): |
|---|
| 97 | return isinstance(resource, models.MediaItem) |
|---|
| 98 | |
|---|
| 99 | @register.filter |
|---|
| 100 | def is_collection(resource): |
|---|
| 101 | return isinstance(resource, models.MediaCollection) |
|---|
| 102 | |
|---|
| 103 | @register.filter |
|---|
| 104 | def to_dublincore(resource): |
|---|
| 105 | if isinstance(resource, models.MediaItem): |
|---|
| 106 | return dc.express_item(resource) |
|---|
| 107 | else: |
|---|
| 108 | return dc.express_collection(resource) |
|---|
| 109 | |
|---|
| 110 | class DescriptionListFieldNode(template.Node): |
|---|
| 111 | def __init__(self, model, attr, join_with = None, show_empty = False): |
|---|
| 112 | self.model = model |
|---|
| 113 | self.member = attr |
|---|
| 114 | self.join_with = join_with |
|---|
| 115 | self.show_empty = show_empty |
|---|
| 116 | |
|---|
| 117 | def render(self, context): |
|---|
| 118 | try: |
|---|
| 119 | model = self.model.resolve(context) |
|---|
| 120 | if isinstance(self.member, template.Variable): |
|---|
| 121 | member = self.member.resolve(context) |
|---|
| 122 | else: |
|---|
| 123 | member = self.member |
|---|
| 124 | label = html.escape(capfirst(unicode(model.field_label(member)))) |
|---|
| 125 | try: |
|---|
| 126 | value = getattr(model, member) |
|---|
| 127 | except AttributeError: |
|---|
| 128 | value = '<ERROR: no such field>' |
|---|
| 129 | except template.VariableDoesNotExist: |
|---|
| 130 | label = unicode(self.model) + '.' + self.member |
|---|
| 131 | value = '<ERROR: can\'t find variable>' |
|---|
| 132 | |
|---|
| 133 | try: |
|---|
| 134 | value = value() |
|---|
| 135 | except TypeError: |
|---|
| 136 | pass |
|---|
| 137 | if self.join_with: |
|---|
| 138 | value = self.join_with.join([unicode(v) for v in value]) |
|---|
| 139 | if not value: |
|---|
| 140 | value = '' |
|---|
| 141 | if value or self.show_empty: |
|---|
| 142 | value = html.escape(unicode(value)) |
|---|
| 143 | markup = '<dt>%s</dt><dd>%s</dd>' % (label, value) |
|---|
| 144 | return markup |
|---|
| 145 | |
|---|
| 146 | return '' |
|---|
| 147 | |
|---|
| 148 | @register.tag |
|---|
| 149 | def dl_field(parser, token): |
|---|
| 150 | cut = token.split_contents() |
|---|
| 151 | join_with = None |
|---|
| 152 | show_empty = False |
|---|
| 153 | if len(cut) == 3: |
|---|
| 154 | tag_name, model, attr = cut |
|---|
| 155 | elif len(cut) == 4: |
|---|
| 156 | tag_name, model, attr, arg3 = cut |
|---|
| 157 | if arg3 == 'placeholder': |
|---|
| 158 | show_empty = True |
|---|
| 159 | else: |
|---|
| 160 | raise ValueError() |
|---|
| 161 | elif len(cut) >= 6: |
|---|
| 162 | tag_name, model, attr, arg3, arg4, arg5 = cut[0:6] |
|---|
| 163 | if arg3 == 'join' and arg4 == 'with'and arg5[0] == arg5[-1] and arg5[0] in ('"', "'"): |
|---|
| 164 | join_with = arg5[1:-1] |
|---|
| 165 | else: |
|---|
| 166 | raise ValueError() |
|---|
| 167 | if len(cut) > 6: |
|---|
| 168 | if cut[6] == 'placeholder': |
|---|
| 169 | show_empty = True |
|---|
| 170 | else: |
|---|
| 171 | raise ValueError(); |
|---|
| 172 | else: |
|---|
| 173 | raise template.TemplateSyntaxError("%r tag: invalid arguments" |
|---|
| 174 | % token.contents.split()[0]) |
|---|
| 175 | |
|---|
| 176 | if attr[0] == attr[-1] and attr[0] in ('"', "'"): |
|---|
| 177 | attr = attr[1:-1] |
|---|
| 178 | else: |
|---|
| 179 | attr = template.Variable(attr) |
|---|
| 180 | model = template.Variable(model) |
|---|
| 181 | return DescriptionListFieldNode(model, attr, join_with=join_with, show_empty=show_empty) |
|---|
| 182 | |
|---|
| 183 | @register.filter |
|---|
| 184 | def prepend(str, prefix): |
|---|
| 185 | if str: |
|---|
| 186 | return prefix + unicode(str) |
|---|
| 187 | return '' |
|---|
| 188 | |
|---|
| 189 | @register.simple_tag |
|---|
| 190 | def field_label(model, field=None): |
|---|
| 191 | if isinstance(model, basestring): |
|---|
| 192 | model = getattr(models, model) |
|---|
| 193 | |
|---|
| 194 | if not field: |
|---|
| 195 | return capfirst(unicode(model._meta.verbose_name)) |
|---|
| 196 | |
|---|
| 197 | return capfirst(unicode(model.field_label(field))) |
|---|
| 198 | |
|---|
| 199 | @register.simple_tag |
|---|
| 200 | def field_value(object, member): |
|---|
| 201 | value = getattr(object, member) |
|---|
| 202 | try: |
|---|
| 203 | value = value() |
|---|
| 204 | except TypeError: |
|---|
| 205 | pass |
|---|
| 206 | return value |
|---|
| 207 | |
|---|
| 208 | @register.filter |
|---|
| 209 | def is_none(value): |
|---|
| 210 | return value is None |
|---|
| 211 | |
|---|
| 212 | @register.filter |
|---|
| 213 | def resources_num(value): |
|---|
| 214 | model = value.model |
|---|
| 215 | count = value.count() |
|---|
| 216 | label = str(count) |
|---|
| 217 | if model == models.MediaItem: |
|---|
| 218 | label = ungettext('%(count)d item', '%(count)d items', count) % { |
|---|
| 219 | 'count': count, } |
|---|
| 220 | elif model == models.MediaCollection: |
|---|
| 221 | label = ungettext('%(count)d collection', '%(count)d collections', count) % { |
|---|
| 222 | 'count': count, } |
|---|
| 223 | |
|---|
| 224 | return label |
|---|
| 225 | |
|---|
| 226 | @register.filter |
|---|
| 227 | def split(value, sep=','): |
|---|
| 228 | return value.split(sep) |
|---|
| 229 | |
|---|
| 230 | @register.simple_tag |
|---|
| 231 | def variable_link(object, url_name, url_key): |
|---|
| 232 | return reverse(url_name, args=[field_value(object, url_key)]) |
|---|
| 233 | |
|---|
| 234 | @register.filter |
|---|
| 235 | def equals(value1, value2): |
|---|
| 236 | return value1 == value2 |
|---|
| 237 | |
|---|
| 238 | @register.filter |
|---|
| 239 | def render_flatpage(content): |
|---|
| 240 | parsed = "" |
|---|
| 241 | path = getattr(content, 'path', '') |
|---|
| 242 | if isinstance(content, basestring): |
|---|
| 243 | content = content.split("\n") |
|---|
| 244 | |
|---|
| 245 | for line in content: |
|---|
| 246 | match = re.match('^(\.\. *(?:_[^:]*:|(?:\|\w+\|)? *image::) *)([^ ]+) *$', line) |
|---|
| 247 | if match: |
|---|
| 248 | directive, urlname = match.groups() |
|---|
| 249 | line = directive |
|---|
| 250 | try: |
|---|
| 251 | i = urlname.index('telemeta-') |
|---|
| 252 | except ValueError: |
|---|
| 253 | i = -1 |
|---|
| 254 | if i == 0: |
|---|
| 255 | line += reverse(urlname) |
|---|
| 256 | elif urlname[:1] != '/': |
|---|
| 257 | line += reverse('telemeta-flatpage', args=[path + '/../' + urlname]) |
|---|
| 258 | else: |
|---|
| 259 | line += urlname |
|---|
| 260 | |
|---|
| 261 | parsed += line + "\n" |
|---|
| 262 | |
|---|
| 263 | parts = publish_parts(source=smart_str(parsed), writer_name="html4css1", settings_overrides={}) |
|---|
| 264 | return mark_safe('<div class="rst-content">\n' + force_unicode(parts["html_body"]) + '</div>') |
|---|
| 265 | render_flatpage.is_safe = True |
|---|
| 266 | |
|---|
| 267 | @register.simple_tag |
|---|
| 268 | def organization(): |
|---|
| 269 | return settings.TELEMETA_ORGANIZATION |
|---|
| 270 | |
|---|
| 271 | @register.simple_tag |
|---|
| 272 | def description(): |
|---|
| 273 | try: |
|---|
| 274 | description = settings.TELEMETA_OAI_REPOSITORY_NAME |
|---|
| 275 | except: |
|---|
| 276 | description = settings.TELEMETA_DESCRIPTION |
|---|
| 277 | pass |
|---|
| 278 | return description |
|---|
| 279 | |
|---|
| 280 | class SetVarNode(template.Node): |
|---|
| 281 | |
|---|
| 282 | def __init__(self, var_name, var_value): |
|---|
| 283 | self.var_name = var_name |
|---|
| 284 | self.var_value = var_value |
|---|
| 285 | |
|---|
| 286 | def render(self, context): |
|---|
| 287 | try: |
|---|
| 288 | value = template.Variable(self.var_value).resolve(context) |
|---|
| 289 | except template.VariableDoesNotExist: |
|---|
| 290 | value = "" |
|---|
| 291 | context[self.var_name] = value |
|---|
| 292 | return u"" |
|---|
| 293 | |
|---|
| 294 | @register.tag |
|---|
| 295 | def set_var(parser, token): |
|---|
| 296 | """ |
|---|
| 297 | {% set <var_name> = <var_value> %} |
|---|
| 298 | """ |
|---|
| 299 | parts = token.split_contents() |
|---|
| 300 | if len(parts) < 4: |
|---|
| 301 | raise template.TemplateSyntaxError("'set' tag must be of the form: {% set <var_name> = <var_value> %}") |
|---|
| 302 | return SetVarNode(parts[1], parts[3]) |
|---|
| 303 | |
|---|
| 304 | @register.simple_tag |
|---|
| 305 | def current_year(): |
|---|
| 306 | return datetime.datetime.now().strftime("%Y") |
|---|
| 307 | |
|---|
| 308 | @register.filter |
|---|
| 309 | def html_line_break(text): |
|---|
| 310 | return text.replace('\n', '<br />') |
|---|
| 311 | |
|---|
| 312 | @register.simple_tag |
|---|
| 313 | def profile(user): |
|---|
| 314 | return user.get_profile() |
|---|