From d9528501cf989779621f5dc67f3e9495ac45bfe5 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Thu, 6 Dec 2012 13:04:40 +0100 Subject: [PATCH] [IMP] qweb doc bzr revid: xmo@openerp.com-20121206120440-17m9q0yhc4osd157 --- addons/web/doc/qweb.rst | 584 +++++++++++++++++++++++++++++++++++----- 1 file changed, 523 insertions(+), 61 deletions(-) diff --git a/addons/web/doc/qweb.rst b/addons/web/doc/qweb.rst index 7ad1e20d57a..47e5fe7d48f 100644 --- a/addons/web/doc/qweb.rst +++ b/addons/web/doc/qweb.rst @@ -1,79 +1,541 @@ - QWeb ==== -QWeb is the template engine used by the OpenERP Web Client. It is a home made engine create by OpenERP developers. There are a few things to note about it: +QWeb is the template engine used by the OpenERP Web Client. It is an +XML-based templating language, similar to `Genshi +`_, +`Thymeleaf `_ or `Facelets +`_ with a few peculiarities: -* Template are rendered in javascript on the client-side, the server does nothing. -* It is an xml template engine, like Facelets_ for example. The source file must be a valid xml. -* Templates are not interpreted. There are compiled to javascript. This makes them a lot faster to render, but sometimes harder to debug. -* Most of the time it is used through the Widget class, but you can also use it directly using *openerp.web.qweb.render()* . +* It's implemented fully in javascript and rendered in the browser. +* Each template file (XML files) contains multiple templates, where + template engine usually have a 1:1 mapping between template files + and templates. +* It has special support in OpenERP Web's + :class:`~instance.web.Widget`, though it can be used outside of + OpenERP Web (and it's possible to use :class:`~instance.web.Widget` + without relying on the QWeb integration). -.. _Facelets: http://en.wikipedia.org/wiki/Facelets +Here's an example demonstrating most of the basic QWeb features: -Here is a typical QWeb file: +.. code-block:: xml -:: - - - -
...
-
- -
...
-
+
+

+
    +
  • + + + +
  • +
+
+ + +
+ +
+
+
+
+
-A QWeb file contains multiple templates, they are simply identified by a name. +rendered with the following context: -Here is a sample QWeb template: +.. code-block:: json -:: + { + "class1": "foo", + "title": "Random Title", + "items": [ + { "name": "foo", "tags": {"bar": "baz", "qux": "quux"} }, + { "name": "Lorem", "tags": { + "ipsum": "dolor", + "sit": "amet", + "consectetur": "adipiscing", + "elit": "Sed", + "hendrerit": "ullamcorper", + "ante": "id", + "vestibulum": "Lorem", + "ipsum": "dolor", + "sit": "amet" + } + } + ] + } - -
-

Name:

-

Password:

-

This user is an Administrator

- -

User has role:

-
-
-
+will yield this section of HTML document (reformated for readability): +.. code-block:: html -*widget* is a variable given to the template engine by Widget sub-classes when they decide to render their associated template, it is simply *this*. Here is the corresponding Widget sub-class: - -:: - - UserPageWidget = openerp.base.Widget.extend({ - template: "UserPage", - init: function(parent) { - this._super(parent); - this.user_name = "Xavier"; - this.password = "lilo"; - this.is_admin = true; - this.roles = ["Web Developer", "IE Hater", "Steve Jobs Worshiper"]; - }, - }); - -It could output something like this: - -:: - -
-

Name: Xavier

-

Password:

-

This user is an Administrator

User has role: Web Developer

-

User has role: IE Hater

-

User has role: Steve Jobs Worshiper

+
+

Random Title

+
    +
  • + foo +
    +
    bar
    +
    baz
    +
    qux
    +
    quux
    +
    +
  • +
  • + Lorem +
    +
    ipsum
    +
    dolor
    +
    sit
    +
    amet
    +
    consectetur
    +
    adipiscing
    +
    elit
    +
    Sed
    +
    hendrerit
    +
    ullamcorper
    +
    +
  • +
-A QWeb template should always contain one unique root element to be used effectively with the Widget class, here it is a *
*. QWeb only react to ** elements or attributes prefixed by *t-*. The ** is simply a null element, it is only used when you need to use a *t-* attribute without outputting an html element at the same time. Here are the effects of the most common QWeb attributes: +API +--- -* *t-esc* outputs the result of the evaluation of the given javascript expression -* *t-att-ATTR* sets the value of the *ATTR* attribute to the result of the evaluation of the given javascript expression -* *t-if* outputs the element and its content only if the given javascript expression returns true -* *t-foreach* outputs as many times as contained in the list returned by the given javascript expression. For each iteration, a variable with the name defined by *t-as* contains the current element in the list. +While QWeb implements a number of attributes and methods for +customization and configuration, only two things are really important +to the user: + +.. js:class:: QWeb2.Engine + + The QWeb "renderer", handles most of QWeb's logic (loading, + parsing, compiling and rendering templates). + + OpenERP Web instantiates one for the user, and sets it to + ``instance.web.qweb``. It also loads all the template files of the + various modules into that QWeb instance. + + A :js:class:`QWeb2.Engine` also serves as a "template namespace". + + .. js:function:: QWeb2.Engine.render(template[, context]) + + Renders a previously loaded template to a String, using + ``context`` (if provided) to find the variables accessed + during template rendering (e.g. strings to display). + + :param String template: the name of the template to render + :param Object context: the basic namespace to use for template + rendering + :returns: String + + The engine exposes an other method which may be useful in some + cases (e.g. if you need a separate template namespace with, in + OpenERP Web, Kanban views get their own :js:class:`QWeb2.Engine` + instance so their templates don't collide with more general + "module" templates): + + .. js:function:: QWeb2.Engine.add_template(templates) + + Loads a template file (a collection of templates) in the QWeb + instance. The templates can be specified as: + + An XML string + QWeb will attempt to parse it to an XML document then load + it. + + A URL + QWeb will attempt to download the URL content, then load + the resulting XML string. + + A ``Document`` or ``Node`` + QWeb will traverse the first level of the document (the + child nodes of the provided root) and load any named + template or template override. + + :type templates: String | Document | Node + + A :js:class:`QWeb2.Engine` also exposes various attributes for + behavior customization: + + .. js:attribute:: QWeb2.Engine.prefix + + Prefix used to recognize :ref:`directives ` + during parsing. A string. By default, ``t``. + + .. js:attribute:: QWeb2.Engine.debug + + Boolean flag putting the engine in "debug mode". Normally, + QWeb intercepts any error raised during template execution. In + debug mode, it leaves all exceptions go through without + intercepting them. + + .. js:attribute:: QWeb2.Engine.jQuery + + The jQuery instance used during :ref:`template inheritance + ` processing. Defaults to + ``window.jQuery``. + + .. js:attribute:: QWeb2.Engine.preprocess_node + + A ``Function``. If present, called before compiling each DOM + node to template code. In OpenERP Web, this is used to + automatically translate text content and some attributes in + templates. Defaults to ``null``. + +.. _qweb-directives: + +Directives +---------- + +A basic QWeb template is nothing more than an XHTML document (as it +must be valid XML), which will be output as-is. But the rendering can +be customized with bits of logic called "directives". Directives are +attributes elements prefixed by :js:attr:`~QWeb2.Engine.prefix` (this +document will use the default prefix ``t``, as does OpenERP Web). + +A directive will usually control or alter the output of the element it +is set on. If no suitable element is available, the prefix itself can +be used as a "no-operation" element solely for supporting directives +(or internal content, which will be rendered). This means: + +.. code-block:: xml + + Something something + +will simply output the string "Something something" (the element +itself will be skipped and "unwrapped"): + +.. code-block:: javascript + + var e = new QWeb2.Engine(); + e.add_template('\ + Test 1\ + Test 2\ + '); + e.render('test1'); // Test 1 + e.render('test2'); // Test 2 + +.. note:: + + The conventions used in directive descriptions are the following: + + * directives are described as compound functions, potentially with + optional sections. Each section of the function name is an + attribute of the element bearing the directive. + + * a special parameter is ``BODY``, which does not have a name and + designates the content of the element. + + * special parameter types (aside from ``BODY`` which remains + untyped) are ``Name``, which designates a valid javascript + variable name, ``Expression`` which designates a valid + javascript expression, and ``Format`` which designates a + Ruby-style format string (a literal string with + ``#{Expression}`` inclusions executed and replaced by their + result) + +.. note:: + + ``Expression`` actually supports a few extensions on the + javascript syntax: because some syntactic elements of javascript + are not compatible with XML and must be escaped, text + substitutions are performed from forms which don't need to be + escaped. Thus the following "keyword operators" are available in + an ``Expression``: ``and`` (maps to ``&&``), ``or`` (maps to + ``||``), ``gt`` (maps to ``>``), ``gte`` (maps to ``>=``), ``lt`` + (maps to ``<``) and ``lte`` (maps to ``<=``). + +.. _qweb-directives-templates: + +Defining Templates +++++++++++++++++++ + +.. _qweb-directive-name: + +.. function:: t-name=name + + :param String name: an arbitrary javascript string. Each template + name is unique in a given + :js:class:`QWeb2.Engine` instance, defining a + new template with an existing name will + overwrite the previous one without warning. + + When multiple templates are related, it is + customary to use dotted names as a kind of + "namespace" e.g. ``foo`` and ``foo.bar`` which + will be used either by ``foo`` or by a + sub-widget of the widget used by ``foo``. + + Templates can only be defined as the children of the document + root. The document root's name is irrelevant (it's not checked) + but is usually ```` for simplicity. + + .. code-block:: xml + + + + + + + + :ref:`t-name ` can be used on an element with + an output as well: + + .. code-block:: xml + + +
+ +
+
+ + which ensures the template has a single root (if a template has + multiple roots and is then passed directly to jQuery, odd things + occur). + +.. _qweb-directives-output: + +Output +++++++ + +.. _qweb-directive-esc: + +.. function:: t-esc=content + + :param Expression content: + + Evaluates, html-escapes and outputs ``content``. + +.. _qweb-directive-escf: + +.. function:: t-escf=content + + :param Format content: + + Similar to :ref:`t-esc ` but evaluates a + ``Format`` instead of just an expression. + +.. _qweb-directive-raw: + +.. function:: t-raw=content + + :param Expression content: + + Similar to :ref:`t-esc ` but does *not* + html-escape the result of evaluating ``content``. Should only ever + be used for known-secure content, or will be an XSS attack vector. + +.. _qweb-directive-rawf: + +.. function:: t-rawf=content + + :param Format content: + + ``Format``-based version of :ref:`t-raw `. + +.. _qweb-directive-att: + +.. function:: t-att=map + + :param Expression map: + + Evaluates ``map`` expecting an ``Object`` result, sets each + key:value pair as an attribute (and its value) on the holder + element: + + .. code-block:: xml + + + + will yield + + .. code-block:: html + + + +.. function:: t-att-ATTNAME=value + + :param Name ATTNAME: + :param Expression value: + + Evaluates ``value`` and sets it on the attribute ``ATTNAME`` on + the holder element. + + If ``value``'s result is ``undefined``, suppresses the creation of + the attribute. + +.. _qweb-directive-attf: + +.. function:: t-attf-ATTNAME=value + + :param Name ATTNAME: + :param Format value: + + Similar to :ref:`t-att-* ` but the value of + the attribute is specified via a ``Format`` instead of an + expression. Useful for specifying e.g. classes mixing literal + classes and computed ones. + +.. _qweb-directives-flow: + +Flow Control +++++++++++++ + +.. _qweb-directive-set: + +.. function:: t-set=name (t-value=value | BODY) + + :param Name name: + :param Expression value: + :param BODY: + + Creates a new binding in the template context. If ``value`` is + specified, evaluates it and sets it to the specified + ``name``. Otherwise, processes ``BODY`` and uses that instead. + +.. _qweb-directive-if: + +.. function:: t-if=condition + + :param Expression condition: + + Evaluates ``condition``, suppresses the output of the holder + element and its content of the result is falsy. + +.. _qweb-directive-foreach: + +.. function:: t-foreach=iterable [t-as=name] + + :param Expression iterable: + :param Name name: + + Evaluates ``iterable``, iterates on it and evaluates the holder + element and its body once per iteration round. + + If ``name`` is not specified, computes a ``name`` based on + ``iterable`` (by replacing non-``Name`` characters by ``_``). + + If ``iterable`` yields a ``Number``, treats it as a range from 0 + to that number (excluded). + + While iterating, :ref:`t-foreach ` adds a + number of variables in the context: + + ``#{name}`` + If iterating on an array (or a range), the current value in + the iteration. If iterating on an *object*, the current key. + ``#{name}_all`` + The collection being iterated (the array generated for a + ``Number``) + ``#{name}_value`` + The current iteration value (current item for an array, value + for the current item for an object) + ``#{name}_index`` + The 0-based index of the current iteration round. + ``#{name}_first`` + Whether the current iteration round is the first one. + ``#{name}_parity`` + ``"odd"`` if the current iteration round is odd, ``"even"`` + otherwise. ``0`` is considered even. + +.. _qweb-directive-call: + +.. function:: t-call=template [BODY] + + :param String template: + :param BODY: + + Calls the specified ``template`` and returns its result. If + ``BODY`` is specified, it is evaluated *before* calling + ``template`` and can be used to specify e.g. parameters. This + usage is similar to `call-template with with-param in XSLT + `_. + +.. _qweb-directives-inheritance: + +Template Inheritance and Extension +++++++++++++++++++++++++++++++++++ + +.. _qweb-directive-extend: + +.. function:: t-extend=template BODY + + :param String template: name of the template to extend + + Works similarly to OpenERP models: if used on its own, will alter + the specified template in-place; if used in conjunction with + :ref:`t-name ` will create a new template + using the old one as a base. + + ``BODY`` should be a sequence of :ref:`t-jquery + ` alteration directives. + + .. note:: + + The inheritance in the second form is *static*: the parent + template is copied and transformed when :ref:`t-extend + ` is called. If it is altered later (by + a :ref:`t-extend ` without a + :ref:`t-name `), these changes will *not* + appear in the "child" templates. + +.. _qweb-directive-jquery: + +.. function:: t-jquery=selector [t-operation=operation] BODY + + :param String selector: a CSS selector into the parent template + :param operation: one of ``append``, ``prepend``, ``before``, + ``after``, ``inner`` or ``replace``. + :param BODY: ``operation`` argument, or alterations to perform + + * If ``operation`` is specified, applies the selector to the + parent template to find a *context node*, then applies + ``operation`` (as a jQuery operation) to the *context node*, + passing ``BODY`` as parameter. + + .. note:: + + ``replace`` maps to jQuery's `replaceWith(newContent) + `_, ``inner`` maps to + `html(htmlString) `_. + + * If ``operation`` is not provided, ``BODY`` is evaluated as + javascript code, with the *context node* as ``this``. + + .. warning:: + + While this second form is much more powerful than the first, + it is also much harder to read and maintain and should be + avoided. It is usually possible to either avoid it or + replace it with a sequence of ``t-jquery:t-operation:``. + +Escape Hatches / debugging +++++++++++++++++++++++++++ + +.. _qweb-directive-log: + +.. function:: t-log=expression + + :param Expression expression: + + Evaluates the provided expression (in the current template + context) and logs its result via ``console.log``. + +.. _qweb-directive-debug: + +.. function:: t-debug + + Injects a debugger breakpoint (via the ``debugger;`` statement) in + the compiled template output. + +.. _qweb-directive-js: + +.. function:: t-js=context BODY + + :param Name context: + :param BODY: javascript code + + Injects the provided ``BODY`` javascript code into the compiled + template, passing it the current template context using the name + specified by ``context``.