Ticket #4529: allowmultipleblocks.diff

File allowmultipleblocks.diff, 7.8 KB (added by Noam Raphael <spam.noam@…>, 8 years ago)
  • django/template/__init__.py

     
    190190    def split_contents(self):
    191191        return list(smart_split(self.contents))
    192192
     193    def __cmp__(self, other):
     194        return cmp((self.token_type, self.contents),
     195                   (other.token_type, other.contents))
     196
    193197class Lexer(object):
    194198    def __init__(self, template_string, origin):
    195199        self.template_string = template_string
     
    251255        self.tokens = tokens
    252256        self.tags = {}
    253257        self.filters = {}
     258        self._token_trackers = {}
    254259        for lib in builtins:
    255260            self.add_library(lib)
    256261
    257     def parse(self, parse_until=None):
    258         if parse_until is None: parse_until = []
    259         nodelist = self.create_nodelist()
    260         while self.tokens:
    261             token = self.next_token()
    262             if token.token_type == TOKEN_TEXT:
    263                 self.extend_nodelist(nodelist, TextNode(token.contents), token)
    264             elif token.token_type == TOKEN_VAR:
    265                 if not token.contents:
    266                     self.empty_variable(token)
    267                 filter_expression = self.compile_filter(token.contents)
    268                 var_node = self.create_variable_node(filter_expression)
    269                 self.extend_nodelist(nodelist, var_node,token)
    270             elif token.token_type == TOKEN_BLOCK:
    271                 if token.contents in parse_until:
    272                     # put token back on token list so calling code knows why it terminated
    273                     self.prepend_token(token)
    274                     return nodelist
    275                 try:
    276                     command = token.contents.split()[0]
    277                 except IndexError:
    278                     self.empty_block_tag(token)
    279                 # execute callback function for this tag and append resulting node
    280                 self.enter_command(command, token)
    281                 try:
    282                     compile_func = self.tags[command]
    283                 except KeyError:
    284                     self.invalid_block_tag(token, command)
    285                 try:
    286                     compiled_result = compile_func(self, token)
    287                 except TemplateSyntaxError, e:
    288                     if not self.compile_function_error(token, e):
    289                         raise
    290                 self.extend_nodelist(nodelist, compiled_result, token)
    291                 self.exit_command()
    292         if parse_until:
    293             self.unclosed_block_tag(parse_until)
    294         return nodelist
     262    def parse(self, parse_until=None, token_tracker=None):
     263        if token_tracker is not None:
     264            self._token_trackers[id(token_tracker)] = token_tracker
     265        try:
     266            if parse_until is None: parse_until = []
     267            nodelist = self.create_nodelist()
     268            while self.tokens:
     269                token = self.next_token()
     270                for x in self._token_trackers.itervalues():
     271                    x.append(token)
     272                if token.token_type == TOKEN_TEXT:
     273                    self.extend_nodelist(nodelist, TextNode(token.contents), token)
     274                elif token.token_type == TOKEN_VAR:
     275                    if not token.contents:
     276                        self.empty_variable(token)
     277                    filter_expression = self.compile_filter(token.contents)
     278                    var_node = self.create_variable_node(filter_expression)
     279                    self.extend_nodelist(nodelist, var_node,token)
     280                elif token.token_type == TOKEN_BLOCK:
     281                    if token.contents in parse_until:
     282                        # put token back on token list so calling code knows why it terminated
     283                        self.prepend_token(token)
     284                        return nodelist
     285                    try:
     286                        command = token.contents.split()[0]
     287                    except IndexError:
     288                        self.empty_block_tag(token)
     289                    # execute callback function for this tag and append resulting node
     290                    self.enter_command(command, token)
     291                    try:
     292                        compile_func = self.tags[command]
     293                    except KeyError:
     294                        self.invalid_block_tag(token, command)
     295                    try:
     296                        compiled_result = compile_func(self, token)
     297                    except TemplateSyntaxError, e:
     298                        if not self.compile_function_error(token, e):
     299                            raise
     300                    self.extend_nodelist(nodelist, compiled_result, token)
     301                    self.exit_command()
     302            if parse_until:
     303                self.unclosed_block_tag(parse_until)
     304            return nodelist
     305        finally:
     306            if token_tracker is not None:
     307                del self._token_trackers[id(token_tracker)]
    295308
    296309    def skip_past(self, endtag):
    297310        while self.tokens:
     
    934947
    935948add_to_builtins('django.template.defaulttags')
    936949add_to_builtins('django.template.defaultfilters')
     950add_to_builtins('django.template.loader_tags')
  • django/template/loader_tags.py

     
    121121    if len(bits) != 2:
    122122        raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
    123123    block_name = bits[1]
    124     # Keep track of the names of BlockNodes found in this template, so we can
    125     # check for duplication.
    126     try:
    127         if block_name in parser.__loaded_blocks:
    128             raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name)
    129         parser.__loaded_blocks.append(block_name)
    130     except AttributeError: # parser.__loaded_blocks isn't a list yet
    131         parser.__loaded_blocks = [block_name]
    132     nodelist = parser.parse(('endblock', 'endblock %s' % block_name))
     124    # If multiple blocks with the same name are defined in the same template,
     125    # all of them must have the same content. To accomplish this, we save
     126    # in the parser all blocks which were already encountered, together with
     127    # the token list from which each one was constructed. When a new block
     128    # with a name that already appeared is encountered, we check if it has
     129    # the same token list, and if so the previously created block is returned.
     130    tokenlist = []
     131    nodelist = parser.parse(('endblock', 'endblock %s' % block_name),
     132                            token_tracker=tokenlist)
    133133    parser.delete_first_token()
    134     return BlockNode(block_name, nodelist)
    135134
     135    try:
     136        loaded_blocks = parser.__loaded_blocks
     137    except AttributeError:
     138        loaded_blocks = parser.__loaded_blocks = {}
     139
     140    try:
     141        prev_block, prev_tokenlist = loaded_blocks[block_name]
     142    except KeyError:
     143        loaded_blocks[block_name] = BlockNode(block_name, nodelist), tokenlist
     144    else:
     145        if prev_tokenlist != tokenlist:
     146            raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once and doesn't have exactly the same contents in all appearances" % (bits[0], block_name)
     147
     148    return loaded_blocks[block_name][0]
     149
    136150def do_extends(parser, token):
    137151    """
    138152    Signal that this template extends a parent template.
  • django/template/loader.py

     
    115115    # If we get here, none of the templates could be loaded
    116116    raise TemplateDoesNotExist, ', '.join(template_name_list)
    117117
    118 add_to_builtins('django.template.loader_tags')
     118#add_to_builtins('django.template.loader_tags')
Back to Top