def _nest_all_elements(tree): """ Manipulate the parse tree by combining all opening and closing html nodes, to reflect the nesting of HTML nodes in the tree. So where '<p>' and '</p>' where two independent siblings in the source three, they become one now, and everything in between is considered a child of this tag. """ # NOTE: this does not yet combile unknown tags, like <fb:like/>, # maybe it's better to replace this code by a more dynamic approach. # Or we can ignore them, like we do know, because we're not unsure # how to thread them. def _create_html_tag_node(name): class tag_node(HtmlTagPair): html_tagname = '' def process_params(self, params): # Create new node for the opening html tag self._open_tag = HtmlTag(name='html-tag') self._open_tag.children = params # Copy line/column number information self._open_tag.line = self.line self._open_tag.column = self.column self._open_tag.path = self.path @property def open_tag(self): return self._open_tag def register_end_node(self, end_node): """ Called by 'nest_block_level_elements' for registering the end node """ self._end_tag = end_node def output(self, handler): handler(self._open_tag) Token.output(self, handler) handler(self._end_tag) tag_node.__name__ = name tag_node.html_tagname = name return tag_node # Parse all other HTML tags, (useful for validation, it checks whether # every opening tag has a closing match. It doesn't hurt, but also doesn't # make much sense to enable this in a production environment.) block_elements2 = { } for t in __ALL_HTML_TAGS: block_elements2[(False, HtmlTag, t)] = ((False, HtmlEndTag, t), _create_html_tag_node(t)) nest_block_level_elements(tree, block_elements2, (HtmlTag, HtmlEndTag), lambda c: (c.is_closing_html_tag, c.__class__, c.html_tagname) )
def _nest_all_elements(tree): """ Manipulate the parse tree by combining all opening and closing html nodes, to reflect the nesting of HTML nodes in the tree. """ def _create_html_tag_node(name): class tag_node(HtmlNode): html_tagname = "" def process_params(self, params): self.__open_tag = HtmlTag() self.__open_tag.children = params @property def open_tag(self): return self.__open_tag def output(self, handler): self.__open_tag.output(handler) Token.output(self, handler) handler("</%s>" % name) tag_node.__name__ = name tag_node.html_tagname = name return tag_node # Parse all other HTML tags, (useful for validation, it checks whether # every opening tag has a closing match. It doesn't hurt, but also doesn't # make much sense to enable this in a production environment.) block_elements2 = {} for t in __ALL_HTML_TAGS: block_elements2[(False, HtmlTag, t)] = ((False, HtmlEndTag, t), _create_html_tag_node(t)) nest_block_level_elements( tree, block_elements2, [HtmlTag, HtmlEndTag], lambda c: (c.is_closing_html_tag, c.__class__, c.html_tagname) )
def _nest_elements(tree): """ Example: Replace (<script>, content, </script>) nodes by a single node, moving the child nodes to the script's content. """ block_elements1 = {"html-start-conditional-comment": ("html-end-conditional-comment", HtmlConditionalComment)} nest_block_level_elements(tree, block_elements1, [Token], lambda c: c.name) # Read as: move the content between: # element of this class, with this html_tagname, and # element of the other class, with the other html_tagname, # to a new parse node of the latter class. block_elements2 = { (False, HtmlTag, "script"): ((False, HtmlEndTag, "script"), HtmlScriptNode), (False, HtmlTag, "style"): ((False, HtmlEndTag, "style"), HtmlStyleNode), (False, HtmlTag, "pre"): ((False, HtmlEndTag, "pre"), HtmlPreNode), (False, HtmlTag, "textarea"): ((False, HtmlEndTag, "textarea"), HtmlTextareaNode), } nest_block_level_elements( tree, block_elements2, [HtmlTag, HtmlEndTag], lambda c: (c.is_closing_html_tag, c.__class__, c.html_tagname) )
def parse(source_code, path, context, main_template=False): """ Parse the code. - source_code: string - path: for attaching meta information to the tree. - context: preprocess context (holding the settings/dependecies/warnings, ...) - main_template: False for includes/extended templates. True for the original path that was called. """ # To start, create the root node of a tree. tree = Token(name="root", line=1, column=1, path=path) tree.children = [source_code] # Lex Django tags tokenize(tree, __DJANGO_STATES, Token) # Phase I: add parser extensions _add_parser_extensions(tree) # Phase II: process inline tags _process_inline_tags(tree) # Phase III: create recursive structure for block level tags. nest_block_level_elements(tree, __DJANGO_BLOCK_ELEMENTS, DjangoTag, lambda c: c.tagname) # === Actions === if main_template: _find_first_level_dependencies(tree, context) # Extend parent template and process includes tree = _process_extends(tree, context) # NOTE: this returns a new tree! _preprocess_includes(tree, context) _preprocess_decorate_tags(tree, context) # Following actions only need to be applied if this is the 'main' tree. # It does not make sense to apply it on every include, and then again # on the complete tree. if main_template: _update_preprocess_settings(tree, context) options = context.options # Remember translations in context (form PO-file generation) remember_gettext_entries(tree, context) # Do translations if options.preprocess_translations: _preprocess_trans_tags(tree) # Reverse URLS if options.preprocess_urls: _preprocess_urls(tree) # Do variable lookups if options.preprocess_variables: sites_enabled = "django.contrib.sites" in settings.INSTALLED_APPS _preprocess_variables( tree, {"MEDIA_URL": getattr(settings, "MEDIA_URL", ""), "STATIC_URL": getattr(settings, "STATIC_URL", "")}, ) if sites_enabled: from django.contrib.sites.models import Site try: # Don't preprocess anything when we don't have a Site # instance yet. site = Site.objects.get_current() _preprocess_variables( tree, {"SITE_DOMAIN": site.domain, "SITE_NAME": site.name, "SITE_URL": "http://%s" % site.domain}, ) except Site.DoesNotExist, e: pass # Don't output {% block %} tags in the compiled file. if options.remove_block_tags: tree.collapse_nodes_of_class(DjangoBlockTag) # Preprocess {% callmacro %} tags if options.preprocess_macros: _preprocess_macros(tree) # Group all {% load %} statements if options.merge_all_load_tags: _group_all_loads(tree) # Preprocessable tags if options.execute_preprocessable_tags: _execute_preprocessable_tags(tree) # HTML compiler if options.is_html: compile_html(tree, context)
def parse(source_code, path, context, main_template=False): """ Parse the code. - source_code: string - path: for attaching meta information to the tree. - context: preprocess context (holding the settings/dependecies/warnings, ...) - main_template: False for includes/extended templates. True for the original path that was called. """ # To start, create the root node of a tree. tree = Token(name='root', line=1, column=1, path=path) tree.children = [ source_code ] # Lex Django tags tokenize(tree, __DJANGO_STATES, Token) # Phase I: add parser extensions _add_parser_extensions(tree) # Phase II: process inline tags _process_inline_tags(tree) # Phase III: create recursive structure for block level tags. nest_block_level_elements(tree, __DJANGO_BLOCK_ELEMENTS, DjangoTag, lambda c: c.tagname) # === Actions === if main_template: _find_first_level_dependencies(tree, context) # Extend parent template and process includes tree = _process_extends(tree, context) # NOTE: this returns a new tree! _preprocess_includes(tree, context) _preprocess_decorate_tags(tree, context) # Following actions only need to be applied if this is the 'main' tree. # It does not make sense to apply it on every include, and then again # on the complete tree. if main_template: _update_preprocess_settings(tree, context) options = context.options # Remember translations in context (form PO-file generation) remember_gettext_entries(tree, context) # Do translations if options.preprocess_translations: _preprocess_trans_tags(tree) # Reverse URLS if options.preprocess_urls: _preprocess_urls(tree) # Do variable lookups if options.preprocess_variables: sites_enabled = 'django.contrib.sites' in settings.INSTALLED_APPS _preprocess_variables(tree, { 'MEDIA_URL': getattr(settings, 'MEDIA_URL', ''), 'STATIC_URL': getattr(settings, 'STATIC_URL', ''), }) if sites_enabled: from django.contrib.sites.models import Site try: # Don't preprocess anything when we don't have a Site # instance yet. site = Site.objects.get_current() _preprocess_variables(tree, { 'SITE_DOMAIN': site.domain, 'SITE_NAME': site.name, 'SITE_URL': 'http://%s' % site.domain, }) except Site.DoesNotExist, e: pass # Don't output {% block %} tags in the compiled file. if options.remove_block_tags: tree.collapse_nodes_of_class(DjangoBlockTag) # Preprocess {% callmacro %} tags if options.preprocess_macros: _preprocess_macros(tree) # Group all {% load %} statements if options.merge_all_load_tags: _group_all_loads(tree) # Preprocessable tags if options.execute_preprocessable_tags: _execute_preprocessable_tags(tree) # HTML compiler if options.is_html: compile_html(tree, context)
def parse(source_code, path, loader, main_template=False, options=None): """ Parse the code. - source_code: string - loader: method to be called to include other templates. - path: for attaching meta information to the tree. - main_template: False for includes/extended templates. True for the original path that was called. """ # To start, create the root node of a tree. tree = Token(name='root', line=1, column=1, path=path) tree.children = [ source_code ] # Lex Django tags tokenize(tree, __DJANGO_STATES, [Token]) # Phase I: add parser extensions _add_parser_extensions(tree) # Phase II: process inline tags _process_inline_tags(tree) # Phase III: create recursive structure for block level tags. nest_block_level_elements(tree, __DJANGO_BLOCK_ELEMENTS, [DjangoTag], lambda c: c.tagname) # === Actions === # Extend parent template and process includes tree = _process_extends(tree, loader) # NOTE: this returns a new tree! _preprocess_includes(tree, loader) _preprocess_decorate_tags(tree, loader) # Following actions only need to be applied if this is the 'main' tree. # It does not make sense to apply it on every include, and then again # on the complete tree. if main_template: options = _get_preprocess_settings(tree, options) # Do translations if options.preprocess_translations: _preprocess_trans_tags(tree) # Reverse URLS if options.preprocess_urls: _preprocess_urls(tree) # Do variable lookups if options.preprocess_variables: from django.contrib.sites.models import Site _preprocess_variables(tree, { 'MEDIA_URL': settings.MEDIA_URL, 'SITE_DOMAIN': Site.objects.get_current().domain, 'SITE_NAME': Site.objects.get_current().name, 'SITE_URL': 'http://%s' % Site.objects.get_current().domain, }) # Don't output {% block %} tags in the compiled file. if options.remove_block_tags: tree.collapse_nodes_of_class(DjangoBlockTag) # Preprocess {% callmacro %} tags if options.preprocess_macros: _preprocess_macros(tree) if options.preprocess_ifdebug: _preprocess_ifdebug(tree) # Group all {% load %} statements if options.merge_all_load_tags: _group_all_loads(tree) # Preprocessable tags if options.execute_preprocessable_tags: _execute_preprocessable_tags(tree) # HTML compiler if options.is_html: compile_html(tree, options) return tree