| 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 os |
|---|
| 16 | import datetime |
|---|
| 17 | from django.conf import settings |
|---|
| 18 | from django.template.defaultfilters import stringfilter |
|---|
| 19 | from django.template import NodeList |
|---|
| 20 | |
|---|
| 21 | register = template.Library() |
|---|
| 22 | |
|---|
| 23 | @register.filter |
|---|
| 24 | def tolist(dict): |
|---|
| 25 | "Converts a simple dict into a list" |
|---|
| 26 | list = [] |
|---|
| 27 | for k, v in dict.iteritems(): |
|---|
| 28 | list.append({'name': k, 'value': v}) |
|---|
| 29 | return list |
|---|
| 30 | |
|---|
| 31 | @register.filter |
|---|
| 32 | def mul(value, arg): |
|---|
| 33 | "Multiply a numeric value" |
|---|
| 34 | return value * arg |
|---|
| 35 | |
|---|
| 36 | class TelemetaVersionNode(template.Node): |
|---|
| 37 | def render(self, context): |
|---|
| 38 | from telemeta import __version__ |
|---|
| 39 | return __version__ |
|---|
| 40 | |
|---|
| 41 | @register.tag |
|---|
| 42 | def telemeta_version(parser, token): |
|---|
| 43 | "Get Telemeta version number" |
|---|
| 44 | return TelemetaVersionNode() |
|---|
| 45 | |
|---|
| 46 | class TelemetaUrlNode(template.Node): |
|---|
| 47 | def render(self, context): |
|---|
| 48 | from telemeta import __url__ |
|---|
| 49 | return __url__ |
|---|
| 50 | |
|---|
| 51 | @register.tag |
|---|
| 52 | def telemeta_url(parser, token): |
|---|
| 53 | "Get Telemeta project homepage URL" |
|---|
| 54 | return TelemetaUrlNode() |
|---|
| 55 | |
|---|
| 56 | _js_escapes = ( |
|---|
| 57 | ('\\', '\\\\'), |
|---|
| 58 | ('"', '\\"'), |
|---|
| 59 | ("'", "\\'"), |
|---|
| 60 | ('\n', '\\n'), |
|---|
| 61 | ('\r', '\\r'), |
|---|
| 62 | ('\b', '\\b'), |
|---|
| 63 | ('\f', '\\f'), |
|---|
| 64 | ('\t', '\\t'), |
|---|
| 65 | ('\v', '\\v'), |
|---|
| 66 | ('</', '<\\/'), |
|---|
| 67 | ) |
|---|
| 68 | @register.filter |
|---|
| 69 | def escapejs(value): |
|---|
| 70 | """Backslash-escapes characters for use in JavaScript strings.""" |
|---|
| 71 | for bad, good in _js_escapes: |
|---|
| 72 | value = value.replace(bad, good) |
|---|
| 73 | return value |
|---|
| 74 | |
|---|
| 75 | @register.filter |
|---|
| 76 | def build_pattern_string(criteria): |
|---|
| 77 | dict = {} |
|---|
| 78 | for c in criteria: |
|---|
| 79 | dict[c.key] = c.value |
|---|
| 80 | return dict |
|---|
| 81 | |
|---|
| 82 | @register.filter |
|---|
| 83 | def build_query_string(vars): |
|---|
| 84 | """Build an HTTP query string out of a dict""" |
|---|
| 85 | if type(vars) == dict: |
|---|
| 86 | import urllib |
|---|
| 87 | args = [] |
|---|
| 88 | for k, v in vars.iteritems(): |
|---|
| 89 | if isinstance(v, db.models.Model): |
|---|
| 90 | v = v.pk |
|---|
| 91 | elif not isinstance(v, basestring): |
|---|
| 92 | v = unicode(v) |
|---|
| 93 | args.append(urlquote(k) + '=' + urlquote(v)) |
|---|
| 94 | |
|---|
| 95 | return "&".join(args) |
|---|
| 96 | return '' |
|---|
| 97 | |
|---|
| 98 | @register.filter |
|---|
| 99 | def with_no_sound(vars): |
|---|
| 100 | _vars = vars.copy() |
|---|
| 101 | if type(_vars) == dict: |
|---|
| 102 | if u'sound' in _vars: |
|---|
| 103 | del _vars[u'sound'] |
|---|
| 104 | return _vars |
|---|
| 105 | |
|---|
| 106 | @register.filter |
|---|
| 107 | def with_sound(vars): |
|---|
| 108 | _vars = vars.copy() |
|---|
| 109 | if type(_vars) == dict: |
|---|
| 110 | if not 'sound' in _vars: |
|---|
| 111 | _vars['sound'] = True |
|---|
| 112 | return _vars |
|---|
| 113 | |
|---|
| 114 | @register.filter |
|---|
| 115 | def code_or_id(resource): |
|---|
| 116 | if resource.code: |
|---|
| 117 | return resource.code |
|---|
| 118 | else: |
|---|
| 119 | return resource.id |
|---|
| 120 | |
|---|
| 121 | @register.filter |
|---|
| 122 | def is_item(resource): |
|---|
| 123 | return isinstance(resource, models.MediaItem) |
|---|
| 124 | |
|---|
| 125 | @register.filter |
|---|
| 126 | def is_collection(resource): |
|---|
| 127 | return isinstance(resource, models.MediaCollection) |
|---|
| 128 | |
|---|
| 129 | @register.filter |
|---|
| 130 | def is_corpus(resource): |
|---|
| 131 | return isinstance(resource, models.MediaCorpus) |
|---|
| 132 | |
|---|
| 133 | @register.filter |
|---|
| 134 | def is_fonds(resource): |
|---|
| 135 | return isinstance(resource, models.MediaFonds) |
|---|
| 136 | |
|---|
| 137 | @register.filter |
|---|
| 138 | def is_resource(resource): |
|---|
| 139 | return is_fonds(resource) or is_corpus(resource) |
|---|
| 140 | |
|---|
| 141 | @register.filter |
|---|
| 142 | def to_dublincore(resource): |
|---|
| 143 | if isinstance(resource, models.MediaItem): |
|---|
| 144 | return dc.express_item(resource) |
|---|
| 145 | elif isinstance(resource, models.MediaCollection): |
|---|
| 146 | return dc.express_collection(resource) |
|---|
| 147 | else: |
|---|
| 148 | return dc.express_generic_resource(resource) |
|---|
| 149 | |
|---|
| 150 | class DescriptionListFieldNode(template.Node): |
|---|
| 151 | def __init__(self, model, attr, join_with = None, show_empty = False): |
|---|
| 152 | self.model = model |
|---|
| 153 | self.member = attr |
|---|
| 154 | self.join_with = join_with |
|---|
| 155 | self.show_empty = show_empty |
|---|
| 156 | |
|---|
| 157 | def render(self, context): |
|---|
| 158 | try: |
|---|
| 159 | model = self.model.resolve(context) |
|---|
| 160 | if isinstance(self.member, template.Variable): |
|---|
| 161 | member = self.member.resolve(context) |
|---|
| 162 | else: |
|---|
| 163 | member = self.member |
|---|
| 164 | label = html.escape(capfirst(unicode(model.field_label(member)))) |
|---|
| 165 | try: |
|---|
| 166 | value = getattr(model, member) |
|---|
| 167 | except AttributeError: |
|---|
| 168 | value = '<ERROR: no such field>' |
|---|
| 169 | except template.VariableDoesNotExist: |
|---|
| 170 | label = unicode(self.model) + '.' + self.member |
|---|
| 171 | value = '<ERROR: can\'t find variable>' |
|---|
| 172 | |
|---|
| 173 | try: |
|---|
| 174 | value = value() |
|---|
| 175 | except TypeError: |
|---|
| 176 | pass |
|---|
| 177 | if self.join_with: |
|---|
| 178 | value = self.join_with.join([unicode(v) for v in value]) |
|---|
| 179 | if not value: |
|---|
| 180 | value = '' |
|---|
| 181 | if value or self.show_empty: |
|---|
| 182 | value = html.escape(unicode(value)) |
|---|
| 183 | markup = '<dt>%s</dt><dd>%s</dd>' % (label, value) |
|---|
| 184 | return markup |
|---|
| 185 | |
|---|
| 186 | return '' |
|---|
| 187 | |
|---|
| 188 | @register.tag |
|---|
| 189 | def dl_field(parser, token): |
|---|
| 190 | cut = token.split_contents() |
|---|
| 191 | join_with = None |
|---|
| 192 | show_empty = False |
|---|
| 193 | if len(cut) == 3: |
|---|
| 194 | tag_name, model, attr = cut |
|---|
| 195 | elif len(cut) == 4: |
|---|
| 196 | tag_name, model, attr, arg3 = cut |
|---|
| 197 | if arg3 == 'placeholder': |
|---|
| 198 | show_empty = True |
|---|
| 199 | else: |
|---|
| 200 | raise ValueError() |
|---|
| 201 | elif len(cut) >= 6: |
|---|
| 202 | tag_name, model, attr, arg3, arg4, arg5 = cut[0:6] |
|---|
| 203 | if arg3 == 'join' and arg4 == 'with'and arg5[0] == arg5[-1] and arg5[0] in ('"', "'"): |
|---|
| 204 | join_with = arg5[1:-1] |
|---|
| 205 | else: |
|---|
| 206 | raise ValueError() |
|---|
| 207 | if len(cut) > 6: |
|---|
| 208 | if cut[6] == 'placeholder': |
|---|
| 209 | show_empty = True |
|---|
| 210 | else: |
|---|
| 211 | raise ValueError(); |
|---|
| 212 | else: |
|---|
| 213 | raise template.TemplateSyntaxError("%r tag: invalid arguments" |
|---|
| 214 | % token.contents.split()[0]) |
|---|
| 215 | |
|---|
| 216 | if attr[0] == attr[-1] and attr[0] in ('"', "'"): |
|---|
| 217 | attr = attr[1:-1] |
|---|
| 218 | else: |
|---|
| 219 | attr = template.Variable(attr) |
|---|
| 220 | model = template.Variable(model) |
|---|
| 221 | return DescriptionListFieldNode(model, attr, join_with=join_with, show_empty=show_empty) |
|---|
| 222 | |
|---|
| 223 | @register.filter |
|---|
| 224 | def prepend(str, prefix): |
|---|
| 225 | if str: |
|---|
| 226 | return prefix + unicode(str) |
|---|
| 227 | return '' |
|---|
| 228 | |
|---|
| 229 | @register.simple_tag |
|---|
| 230 | def field_label(model, field=None): |
|---|
| 231 | if isinstance(model, basestring): |
|---|
| 232 | model = getattr(models, model) |
|---|
| 233 | |
|---|
| 234 | if not field: |
|---|
| 235 | return capfirst(unicode(model._meta.verbose_name)) |
|---|
| 236 | |
|---|
| 237 | return capfirst(unicode(model.field_label(field))) |
|---|
| 238 | |
|---|
| 239 | @register.simple_tag |
|---|
| 240 | def field_value(object, member): |
|---|
| 241 | value = getattr(object, member) |
|---|
| 242 | try: |
|---|
| 243 | value = value() |
|---|
| 244 | except TypeError: |
|---|
| 245 | pass |
|---|
| 246 | return value |
|---|
| 247 | |
|---|
| 248 | @register.filter |
|---|
| 249 | def is_none(value): |
|---|
| 250 | return value is None |
|---|
| 251 | |
|---|
| 252 | @register.filter |
|---|
| 253 | def resources_num(value): |
|---|
| 254 | model = value.model |
|---|
| 255 | count = value.count() |
|---|
| 256 | label = str(count) |
|---|
| 257 | if model == models.MediaItem: |
|---|
| 258 | label = ungettext('%(count)d item', '%(count)d items', count) % { |
|---|
| 259 | 'count': count, } |
|---|
| 260 | elif model == models.MediaCollection: |
|---|
| 261 | label = ungettext('%(count)d collection', '%(count)d collections', count) % { |
|---|
| 262 | 'count': count, } |
|---|
| 263 | |
|---|
| 264 | return label |
|---|
| 265 | |
|---|
| 266 | @register.filter |
|---|
| 267 | def split(value, sep=','): |
|---|
| 268 | return value.split(sep) |
|---|
| 269 | |
|---|
| 270 | @register.simple_tag |
|---|
| 271 | def variable_link(object, url_name, url_key): |
|---|
| 272 | return reverse(url_name, args=[field_value(object, url_key)]) |
|---|
| 273 | |
|---|
| 274 | @register.filter |
|---|
| 275 | def equals(value1, value2): |
|---|
| 276 | return value1 == value2 |
|---|
| 277 | |
|---|
| 278 | @register.filter |
|---|
| 279 | def render_flatpage(content): |
|---|
| 280 | parsed = "" |
|---|
| 281 | path = getattr(content, 'path', '') |
|---|
| 282 | if isinstance(content, basestring): |
|---|
| 283 | content = content.split("\n") |
|---|
| 284 | |
|---|
| 285 | for line in content: |
|---|
| 286 | match = re.match('^(\.\. *(?:_[^:]*:|(?:\|\w+\|)? *image::) *)([^ ]+) *$', line) |
|---|
| 287 | if match: |
|---|
| 288 | directive, urlname = match.groups() |
|---|
| 289 | line = directive |
|---|
| 290 | try: |
|---|
| 291 | i = urlname.index('telemeta-') |
|---|
| 292 | except ValueError: |
|---|
| 293 | i = -1 |
|---|
| 294 | if i == 0: |
|---|
| 295 | line += reverse(urlname) |
|---|
| 296 | elif urlname[:1] != '/': |
|---|
| 297 | line += reverse('telemeta-flatpage', args=[path + '/../' + urlname]) |
|---|
| 298 | else: |
|---|
| 299 | line += urlname |
|---|
| 300 | |
|---|
| 301 | parsed += line + "\n" |
|---|
| 302 | |
|---|
| 303 | parts = publish_parts(source=smart_str(parsed), writer_name="html4css1", settings_overrides={}) |
|---|
| 304 | return mark_safe('<div class="rst-content">\n' + force_unicode(parts["html_body"]) + '</div>') |
|---|
| 305 | render_flatpage.is_safe = True |
|---|
| 306 | |
|---|
| 307 | @register.simple_tag |
|---|
| 308 | def organization(): |
|---|
| 309 | return settings.TELEMETA_ORGANIZATION |
|---|
| 310 | |
|---|
| 311 | @register.simple_tag |
|---|
| 312 | def description(): |
|---|
| 313 | try: |
|---|
| 314 | description = settings.TELEMETA_OAI_REPOSITORY_NAME |
|---|
| 315 | except: |
|---|
| 316 | description = settings.TELEMETA_DESCRIPTION |
|---|
| 317 | pass |
|---|
| 318 | return description |
|---|
| 319 | |
|---|
| 320 | class SetVarNode(template.Node): |
|---|
| 321 | |
|---|
| 322 | def __init__(self, var_name, var_value): |
|---|
| 323 | self.var_name = var_name |
|---|
| 324 | self.var_value = var_value |
|---|
| 325 | |
|---|
| 326 | def render(self, context): |
|---|
| 327 | try: |
|---|
| 328 | value = template.Variable(self.var_value).resolve(context) |
|---|
| 329 | except template.VariableDoesNotExist: |
|---|
| 330 | value = "" |
|---|
| 331 | context[self.var_name] = value |
|---|
| 332 | return u"" |
|---|
| 333 | |
|---|
| 334 | @register.tag |
|---|
| 335 | def set_var(parser, token): |
|---|
| 336 | """ |
|---|
| 337 | {% set <var_name> = <var_value> %} |
|---|
| 338 | """ |
|---|
| 339 | parts = token.split_contents() |
|---|
| 340 | if len(parts) < 4: |
|---|
| 341 | raise template.TemplateSyntaxError("'set' tag must be of the form: {% set <var_name> = <var_value> %}") |
|---|
| 342 | return SetVarNode(parts[1], parts[3]) |
|---|
| 343 | |
|---|
| 344 | @register.simple_tag |
|---|
| 345 | def current_year(): |
|---|
| 346 | return datetime.datetime.now().strftime("%Y") |
|---|
| 347 | |
|---|
| 348 | @register.filter |
|---|
| 349 | def html_line_break(text): |
|---|
| 350 | return text.replace('\n', '<br />') |
|---|
| 351 | |
|---|
| 352 | @register.simple_tag |
|---|
| 353 | def profile(user): |
|---|
| 354 | return user.get_profile() |
|---|
| 355 | |
|---|
| 356 | @register.filter |
|---|
| 357 | def to_string(list): |
|---|
| 358 | if len(list) != 0: |
|---|
| 359 | return list[0].encode('utf-8') |
|---|
| 360 | else: |
|---|
| 361 | return '' |
|---|
| 362 | |
|---|
| 363 | @register.filter |
|---|
| 364 | def get_filename(object): |
|---|
| 365 | if isinstance(object, unicode): |
|---|
| 366 | return object.split('/')[-1] |
|---|
| 367 | else: |
|---|
| 368 | return object.path.split(os.sep)[-1] |
|---|
| 369 | |
|---|
| 370 | @register.filter |
|---|
| 371 | def get_youtube(link): |
|---|
| 372 | link = link.split('&') |
|---|
| 373 | if "=" in link[0]: |
|---|
| 374 | ref = link[0].split('=')[1] |
|---|
| 375 | else: |
|---|
| 376 | ref = link[0].split('/')[-1] |
|---|
| 377 | return 'http://www.youtube.com/embed/'+ref |
|---|
| 378 | |
|---|
| 379 | @register.filter |
|---|
| 380 | def to_utf8(word): |
|---|
| 381 | return word.encode('utf-8') |
|---|
| 382 | |
|---|
| 383 | @register.filter |
|---|
| 384 | @stringfilter |
|---|
| 385 | def capitalize(value): |
|---|
| 386 | return value.capitalize() |
|---|
| 387 | |
|---|
| 388 | @register.filter |
|---|
| 389 | @stringfilter |
|---|
| 390 | def mime_to_ext(mime_type): |
|---|
| 391 | return mime_type.split('/')[1] |
|---|
| 392 | |
|---|
| 393 | @register.filter |
|---|
| 394 | @stringfilter |
|---|
| 395 | def mime_to_media_type(mime_type): |
|---|
| 396 | if 'video' in mime_type: |
|---|
| 397 | return 'Video' |
|---|
| 398 | else: |
|---|
| 399 | return 'Audio' |
|---|
| 400 | |
|---|
| 401 | |
|---|
| 402 | def do_ifloaded(parser, token): |
|---|
| 403 | bits = token.split_contents()[1:] |
|---|
| 404 | var = bits[0] |
|---|
| 405 | nodelist_true = parser.parse(('else', 'endifloaded')) |
|---|
| 406 | token = parser.next_token() |
|---|
| 407 | if token.contents == 'else': |
|---|
| 408 | nodelist_false = parser.parse(('endifloaded',)) |
|---|
| 409 | parser.delete_first_token() |
|---|
| 410 | else: |
|---|
| 411 | nodelist_false = NodeList() |
|---|
| 412 | return IfLoadedNode(var, nodelist_true, nodelist_false) |
|---|
| 413 | register.tag('ifloaded', do_ifloaded) |
|---|
| 414 | |
|---|
| 415 | |
|---|
| 416 | class IfLoadedNode(template.Node): |
|---|
| 417 | def __init__(self, var, nodelist_true, nodelist_false=None): |
|---|
| 418 | self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false |
|---|
| 419 | self.var = var |
|---|
| 420 | |
|---|
| 421 | def __repr__(self): |
|---|
| 422 | return '<IfLoaded node>' |
|---|
| 423 | |
|---|
| 424 | def __iter__(self): |
|---|
| 425 | for node in self.nodelist_true: |
|---|
| 426 | yield node |
|---|
| 427 | for node in self.nodelist_false: |
|---|
| 428 | yield node |
|---|
| 429 | |
|---|
| 430 | def get_nodes_by_type(self, nodetype): |
|---|
| 431 | nodes = [] |
|---|
| 432 | if isinstance(self, nodetype): |
|---|
| 433 | nodes.append(self) |
|---|
| 434 | nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype)) |
|---|
| 435 | nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype)) |
|---|
| 436 | return nodes |
|---|
| 437 | |
|---|
| 438 | def render(self, context): |
|---|
| 439 | for app in settings.INSTALLED_APPS: |
|---|
| 440 | if str(app) == str(self.var): |
|---|
| 441 | return self.nodelist_true.render(context) |
|---|
| 442 | return self.nodelist_false.render(context) |
|---|