Highlighted url: http://webnewage.org/media/upload/filecache/switchcase.py
Type: Python
| 1 | # -*- coding: utf-8 -*- |
| 2 | #-------------------------------- |
| 3 | #$Date$ |
| 4 | #$Author$ |
| 5 | #$Revision$ |
| 6 | #-------------------------------- |
| 7 | #Copyright (C) 2007 Alexander Koshelev (daevaorn@gmail.com) |
| 8 | """ |
| 9 | Switch/case/default tag for Django. |
| 10 | Based on original idea of jacobian's snippest http://www.djangosnippets.org/snippets/300/ |
| 11 | |
| 12 | Usage:: |
| 13 | |
| 14 | {% load switchcase %} |
| 15 | {% switch meal %} |
| 16 | {% case "spam" %}...{% endcase %} |
| 17 | {% case "eggs" "appels"%}...{% endcase %} |
| 18 | {% default %}...{% enddefault %} |
| 19 | {% endswitch %} |
| 20 | """ |
| 21 | from django import template |
| 22 | |
| 23 | register = template.Library() |
| 24 | |
| 25 | @register.tag |
| 26 | def switch(parser, token): |
| 27 | """ |
| 28 | Switch tag. Usage:: |
| 29 | |
| 30 | {% switch meal %} |
| 31 | {% case "spam" %}...{% endcase %} |
| 32 | {% case "eggs" %}...{% endcase %} |
| 33 | {% endswitch %} |
| 34 | |
| 35 | Note that ``{% case %}`` arguments can be variables if you like (as can |
| 36 | switch arguments, buts that's a bit silly). |
| 37 | """ |
| 38 | # Parse out the arguments. |
| 39 | args = token.split_contents() |
| 40 | if len(args) != 2: |
| 41 | raise template.TemplateSyntaxError("%s tag tags exactly 2 arguments." % args[0]) |
| 42 | |
| 43 | # Pull out all the children of the switch tag (until {% endswitch %}). |
| 44 | childnodes = parser.parse(("endswitch",)) |
| 45 | |
| 46 | # Remove the {% endswitch %} node so it doesn't get parsed twice. |
| 47 | parser.delete_first_token() |
| 48 | |
| 49 | # We just care about case children; all other direct children get ignored. |
| 50 | casenodes = childnodes.get_nodes_by_type(CaseNode) |
| 51 | default = childnodes.get_nodes_by_type(DefaultNode) |
| 52 | assert( len( default) < 2 ) |
| 53 | |
| 54 | |
| 55 | return SwitchNode(args[1], casenodes, len( default ) and default[ 0 ] or None ) |
| 56 | |
| 57 | @register.tag |
| 58 | def case(parser, token): |
| 59 | """ |
| 60 | Case tag. Used only inside ``{% switch %}`` tags, so see above for those docs. |
| 61 | """ |
| 62 | args = token.split_contents() |
| 63 | #assert len(args) == 2 |
| 64 | |
| 65 | # Same dance as above, except this time we care about all the child nodes |
| 66 | children = parser.parse(("endcase",)) |
| 67 | parser.delete_first_token() |
| 68 | return CaseNode(args[1:], children) |
| 69 | |
| 70 | @register.tag |
| 71 | def default(parser, token ): |
| 72 | """ |
| 73 | """ |
| 74 | args = token.split_contents() |
| 75 | assert len(args) == 1 |
| 76 | |
| 77 | children = parser.parse(("enddefault",)) |
| 78 | parser.delete_first_token() |
| 79 | |
| 80 | return DefaultNode(children) |
| 81 | |
| 82 | class SwitchNode(template.Node): |
| 83 | def __init__(self, value, cases, default): |
| 84 | self.value = value |
| 85 | self.cases = cases |
| 86 | self.default = default |
| 87 | |
| 88 | def render(self, context): |
| 89 | # Resolve the value; if it's a non-existant variable don't even bother |
| 90 | # checking the values of the cases since they'll never match. |
| 91 | try: |
| 92 | value = template.resolve_variable(self.value, context) |
| 93 | except template.VariableDoesNotExist: |
| 94 | return "" |
| 95 | |
| 96 | # Check each case, and if it matches return the rendered content |
| 97 | # of that case (short-circuit). |
| 98 | for case in self.cases: |
| 99 | if case.equals(value, context): |
| 100 | return case.render(context) |
| 101 | if self.default: |
| 102 | return self.default.render( context ) |
| 103 | |
| 104 | # No matches and no default; render nothing. |
| 105 | return "" |
| 106 | |
| 107 | class CaseNode(template.Node): |
| 108 | def __init__(self, values, childnodes): |
| 109 | self.values = values |
| 110 | self.childnodes = childnodes |
| 111 | |
| 112 | def equals(self, otherval, context): |
| 113 | """ |
| 114 | Check to see if this case's value equals some other value. This is |
| 115 | called from ``SwitchNode.render()``, above. |
| 116 | """ |
| 117 | try: |
| 118 | for value in self.values: |
| 119 | if template.resolve_variable( value, context) == otherval: |
| 120 | return True |
| 121 | return False |
| 122 | except template.VariableDoesNotExist: |
| 123 | # If the variable doesn't exist, it doesn't equal anything. |
| 124 | return False |
| 125 | |
| 126 | def render(self, context): |
| 127 | """Render this particular case, which means rendering its child nodes.""" |
| 128 | return self.childnodes.render(context) |
| 129 | |
| 130 | class DefaultNode( template.Node ): |
| 131 | def __init__(self, childnodes): |
| 132 | self.childnodes = childnodes |
| 133 | |
| 134 | def render(self, context): |
| 135 | """Render this default, which means rendering its child nodes.""" |
| 136 | return self.childnodes.render(context) |
| 137 |
