Edgewall Software

Changes between Version 40 and Version 41 of TracDev/PortingFromGenshiToJinja


Ignore:
Timestamp:
Jan 28, 2017, 12:14:31 AM (7 years ago)
Author:
Christian Boos
Comment:

move the #Generatingcontent section before the "Modifying content" one

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/PortingFromGenshiToJinja

    v40 v41  
    598598
    599599Note that as long as we have to support the legacy Genshi templates, a `None` value passed as third argument won't be interpreted as an empty `dict`, but rather as an empty `content_type`.
     600
     601
     602
     603=== Generating content
     604
     605==== Rendering template "fragments"
     606When one wants to directly render a template, the Chrome `render_template` can still be used, as before:
     607{{{#!py
     608return Chrome(self.env).render_template(
     609                req, 'query_results.html', data, None, fragment=True)
     610}}}
     611However, `render_template` prepares all the data needed to render a page in the full default layout. It also now consistently returns an output that is prepared to be sent back to the client. So if you need to embed the generated content in other generated content, this method is the best choice.
     612
     613`render_fragment` can be used instead. It returns a `Markup` string when generating output for the web (`text=False`) or an `unicode` string when generating plain text output (`text=True`).
     614
     615//See [source:cboos.git/trac/ticket/query.py@jinja2-trunk-r15379#L1423 Ticket Query] macro (''table'' mode)//
     616
     617When the fragment needs to be sent to the client, there's still a better choice than `render_template`, it's `generate_fragment`, as it won't impose as much overhead on the data dictionary as `render_template`. It's best suited for responding to XHRs:
     618{{{#!python
     619        if req.is_xhr:  # render and return the content only
     620            stream = Chrome(self.env).generate_fragment(
     621                req, 'changeset_content.html', data)
     622            req.send(stream)
     623}}}
     624
     625This automatically retrieves the `use_chunked_encoding` TracIni setting and uses it to return an iterable.  In any case, the returned value can be sent directly from the `Request` object.
     626
     627There's even a lower-level public API in `Chrome` for generating content using Jinja2 templates, which provides even greater control.
     628//See the [source:cboos.git/trac/ticket/notification.py@jinja2-trunk-r15379#L311 rendering of the ticket change notification e-mail]//
     629
     630See the API documentation for further details.
     631
     632
     633==== The `tag` builder #tag
     634
     635Genshi provided a nice Python API for programmatically building (X)HTML elements. This consisted of the `Fragment`, `Element` and the `tag` builder, all from the `genshi.builder` module:
     636{{{#!python
     637from genshi import Fragment, Element, tag
     638}}}
     639This has now been replaced by an equivalent API which lives in `trac.util.html`, so the above import should be replaced with:
     640{{{#!python
     641from trac.util.html import Fragment, Element, tag
     642}}}
     643Note that the `html` symbol from `trac.util.html` which used to be a alias to `genshi.builder.tag` is now naturally an alias to `trac.util.html.tag`.
     644
     645One way to write "portable" code would be:
     646{{{#!python
     647from trac.util.html import html as tag
     648}}}
     649You can then use the `tag` builder API regardless of its origin.
     650
     651
     652The behavior of the new `tag` builder is nearly the same as the old one,
     653except that it has even more "knowledge" about the HTML format. For example, for the `class` attribute (or rather, `class_` as `class` is a reserved Python keyword), and for the `style` attribute, dicts can be given as parameters instead of plain strings. Other attributes, like `checked`, will be omitted when given a `False` value.
     654
     655As this special behavior could be unwanted when arbitrary XML must be generated instead of XHTML, another builder, `xml`, is now available. The `xml` builder can be used the same way as the `tag` builder, but when serialized, its only special behavior is to omit attributes which have the value `None`.
     656
     657==== The `Markup` class
     658
     659Likewise, if you want to use the `Markup` class, you should write:
     660{{{#!python
     661from trac.util.html import Markup
     662}}}
     663In "old" versions of Trac, you'll get `genshi.core.Markup`, whereas now you'll get `markupsafe.Markup`: as we're using Jinja2, we're also making use of its direct dependency [PyPI:MarkupSafe].
     664
     665==== The `escape` function
     666
     667{{{#!python
     668from trac.util.html import escape
     669}}}
     670Note that in a similar way to `Markup`, `escape` now also comes from `markupsafe`, with some slight adaptations, as `markupsafe.escape` always escapes the quotes, which is something we don't do by default. Hence always import `escape` from `trac.util.html`, never directly from `markupsafe` or Jinja2, unless you really know what you're doing.
    600671
    601672
     
    822893See the full changeset, [bf49f871/cboos.git] (and [be0ff94a/cboos.git] for a look to the generated .js).
    823894
    824 === Generating content
    825 
    826 ==== Rendering template "fragments"
    827 When one wants to directly render a template, the Chrome `render_template` can still be used, as before:
    828 {{{#!py
    829 return Chrome(self.env).render_template(
    830                 req, 'query_results.html', data, None, fragment=True)
    831 }}}
    832 However, `render_template` prepares all the data needed to render a page in the full default layout. It also now consistently returns an output that is prepared to be sent back to the client. So if you need to embed the generated content in other generated content, this method is the best choice.
    833 
    834 `render_fragment` can be used instead. It returns a `Markup` string when generating output for the web (`text=False`) or an `unicode` string when generating plain text output (`text=True`).
    835 
    836 //See [source:cboos.git/trac/ticket/query.py@jinja2-trunk-r15379#L1423 Ticket Query] macro (''table'' mode)//
    837 
    838 When the fragment needs to be sent to the client, there's still a better choice than `render_template`, it's `generate_fragment`, as it won't impose as much overhead on the data dictionary as `render_template`. It's best suited for responding to XHRs:
    839 {{{#!python
    840         if req.is_xhr:  # render and return the content only
    841             stream = Chrome(self.env).generate_fragment(
    842                 req, 'changeset_content.html', data)
    843             req.send(stream)
    844 }}}
    845 
    846 This automatically retrieves the `use_chunked_encoding` TracIni setting and uses it to return an iterable.  In any case, the returned value can be sent directly from the `Request` object.
    847 
    848 There's even a lower-level public API in `Chrome` for generating content using Jinja2 templates, which provides even greater control.
    849 //See the [source:cboos.git/trac/ticket/notification.py@jinja2-trunk-r15379#L311 rendering of the ticket change notification e-mail]//
    850 
    851 See the API documentation for further details.
    852 
    853 
    854 ==== The `tag` builder #tag
    855 
    856 Genshi provided a nice Python API for programmatically building (X)HTML elements. This consisted of the `Fragment`, `Element` and the `tag` builder, all from the `genshi.builder` module:
    857 {{{#!python
    858 from genshi import Fragment, Element, tag
    859 }}}
    860 This has now been replaced by an equivalent API which lives in `trac.util.html`, so the above import should be replaced with:
    861 {{{#!python
    862 from trac.util.html import Fragment, Element, tag
    863 }}}
    864 Note that the `html` symbol from `trac.util.html` which used to be a alias to `genshi.builder.tag` is now naturally an alias to `trac.util.html.tag`.
    865 
    866 One way to write "portable" code would be:
    867 {{{#!python
    868 from trac.util.html import html as tag
    869 }}}
    870 You can then use the `tag` builder API regardless of its origin.
    871 
    872 
    873 The behavior of the new `tag` builder is nearly the same as the old one,
    874 except that it has even more "knowledge" about the HTML format. For example, for the `class` attribute (or rather, `class_` as `class` is a reserved Python keyword), and for the `style` attribute, dicts can be given as parameters instead of plain strings. Other attributes, like `checked`, will be omitted when given a `False` value.
    875 
    876 As this special behavior could be unwanted when arbitrary XML must be generated instead of XHTML, another builder, `xml`, is now available. The `xml` builder can be used the same way as the `tag` builder, but when serialized, its only special behavior is to omit attributes which have the value `None`.
    877 
    878 ==== The `Markup` class
    879 
    880 Likewise, if you want to use the `Markup` class, you should write:
    881 {{{#!python
    882 from trac.util.html import Markup
    883 }}}
    884 In "old" versions of Trac, you'll get `genshi.core.Markup`, whereas now you'll get `markupsafe.Markup`: as we're using Jinja2, we're also making use of its direct dependency [PyPI:MarkupSafe].
    885 
    886 ==== The `escape` function
    887 
    888 {{{#!python
    889 from trac.util.html import escape
    890 }}}
    891 Note that in a similar way to `Markup`, `escape` now also comes from `markupsafe`, with some slight adaptations, as `markupsafe.escape` always escapes the quotes, which is something we don't do by default. Hence always import `escape` from `trac.util.html`, never directly from `markupsafe` or Jinja2, unless you really know what you're doing.
    892 
     895