| 600 | |
| 601 | |
| 602 | |
| 603 | === Generating content |
| 604 | |
| 605 | ==== Rendering template "fragments" |
| 606 | When one wants to directly render a template, the Chrome `render_template` can still be used, as before: |
| 607 | {{{#!py |
| 608 | return Chrome(self.env).render_template( |
| 609 | req, 'query_results.html', data, None, fragment=True) |
| 610 | }}} |
| 611 | 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. |
| 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 | |
| 617 | 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: |
| 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 | |
| 625 | 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. |
| 626 | |
| 627 | There'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 | |
| 630 | See the API documentation for further details. |
| 631 | |
| 632 | |
| 633 | ==== The `tag` builder #tag |
| 634 | |
| 635 | 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: |
| 636 | {{{#!python |
| 637 | from genshi import Fragment, Element, tag |
| 638 | }}} |
| 639 | This has now been replaced by an equivalent API which lives in `trac.util.html`, so the above import should be replaced with: |
| 640 | {{{#!python |
| 641 | from trac.util.html import Fragment, Element, tag |
| 642 | }}} |
| 643 | 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`. |
| 644 | |
| 645 | One way to write "portable" code would be: |
| 646 | {{{#!python |
| 647 | from trac.util.html import html as tag |
| 648 | }}} |
| 649 | You can then use the `tag` builder API regardless of its origin. |
| 650 | |
| 651 | |
| 652 | The behavior of the new `tag` builder is nearly the same as the old one, |
| 653 | 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. |
| 654 | |
| 655 | 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`. |
| 656 | |
| 657 | ==== The `Markup` class |
| 658 | |
| 659 | Likewise, if you want to use the `Markup` class, you should write: |
| 660 | {{{#!python |
| 661 | from trac.util.html import Markup |
| 662 | }}} |
| 663 | 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]. |
| 664 | |
| 665 | ==== The `escape` function |
| 666 | |
| 667 | {{{#!python |
| 668 | from trac.util.html import escape |
| 669 | }}} |
| 670 | 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. |
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 | |