[IMP] web: documents the new module system.
This add a basic overview of how the modules work. This is a work in progress, more documentation needs to be updated, such as the tutorial.
This commit is contained in:
+186
-70
@@ -9,11 +9,11 @@ Javascript
|
||||
Widgets
|
||||
=======
|
||||
|
||||
.. class:: openerp.Widget
|
||||
.. class:: Widget
|
||||
|
||||
The base class for all visual components. It corresponds to an MVC
|
||||
view, and provides a number of service to simplify handling of a section
|
||||
of a page:
|
||||
Exported in ``web.Widget``, the base class for all visual components.
|
||||
It corresponds to an MVC view, and provides a number of service to
|
||||
simplify handling of a section of a page:
|
||||
|
||||
* Handles parent/child relationships between widgets
|
||||
* Provides extensive lifecycle management with safety features (e.g.
|
||||
@@ -25,45 +25,45 @@ Widgets
|
||||
DOM Root
|
||||
--------
|
||||
|
||||
A :class:`~openerp.Widget` is responsible for a section of the page
|
||||
A :class:`~Widget` is responsible for a section of the page
|
||||
materialized by the DOM root of the widget.
|
||||
|
||||
A widget's DOM root is available via two attributes:
|
||||
|
||||
.. attribute:: openerp.Widget.el
|
||||
.. attribute:: Widget.el
|
||||
|
||||
raw DOM element set as root to the widget
|
||||
|
||||
.. attribute:: openerp.Widget.$el
|
||||
.. attribute:: Widget.$el
|
||||
|
||||
jQuery wrapper around :attr:`~openerp.Widget.el`
|
||||
jQuery wrapper around :attr:`~Widget.el`
|
||||
|
||||
There are two main ways to define and generate this DOM root:
|
||||
|
||||
.. attribute:: openerp.Widget.template
|
||||
.. attribute:: Widget.template
|
||||
|
||||
Should be set to the name of a :ref:`QWeb template <reference/qweb>`.
|
||||
If set, the template will be rendered after the widget has been
|
||||
initialized but before it has been started. The root element generated by
|
||||
the template will be set as the DOM root of the widget.
|
||||
|
||||
.. attribute:: openerp.Widget.tagName
|
||||
.. attribute:: Widget.tagName
|
||||
|
||||
Used if the widget has no template defined. Defaults to ``div``,
|
||||
will be used as the tag name to create the DOM element to set as
|
||||
the widget's DOM root. It is possible to further customize this
|
||||
generated DOM root with the following attributes:
|
||||
|
||||
.. attribute:: openerp.Widget.id
|
||||
.. attribute:: Widget.id
|
||||
|
||||
Used to generate an ``id`` attribute on the generated DOM
|
||||
root.
|
||||
|
||||
.. attribute:: openerp.Widget.className
|
||||
.. attribute:: Widget.className
|
||||
|
||||
Used to generate a ``class`` attribute on the generated DOM root.
|
||||
|
||||
.. attribute:: openerp.Widget.attributes
|
||||
.. attribute:: Widget.attributes
|
||||
|
||||
Mapping (object literal) of attribute names to attribute
|
||||
values. Each of these k:v pairs will be set as a DOM attribute
|
||||
@@ -73,25 +73,25 @@ There are two main ways to define and generate this DOM root:
|
||||
|
||||
The DOM root can also be defined programmatically by overridding
|
||||
|
||||
.. function:: openerp.Widget.renderElement
|
||||
.. function:: Widget.renderElement
|
||||
|
||||
Renders the widget's DOM root and sets it. The default
|
||||
implementation will render a set template or generate an element
|
||||
as described above, and will call
|
||||
:func:`~openerp.Widget.setElement` on the result.
|
||||
:func:`~Widget.setElement` on the result.
|
||||
|
||||
Any override to :func:`~openerp.Widget.renderElement` which
|
||||
Any override to :func:`~Widget.renderElement` which
|
||||
does not call its ``_super`` **must** call
|
||||
:func:`~openerp.Widget.setElement` with whatever it
|
||||
:func:`~Widget.setElement` with whatever it
|
||||
generated or the widget's behavior is undefined.
|
||||
|
||||
.. note::
|
||||
|
||||
The default :func:`~openerp.Widget.renderElement` can
|
||||
The default :func:`~Widget.renderElement` can
|
||||
be called repeatedly, it will *replace* the previous DOM root
|
||||
(using ``replaceWith``). However, this requires that the
|
||||
widget correctly sets and unsets its events (and children
|
||||
widgets). Generally, :func:`~openerp.Widget.renderElement` should
|
||||
widgets). Generally, :func:`~Widget.renderElement` should
|
||||
not be called repeatedly unless the widget advertizes this feature.
|
||||
|
||||
Using a widget
|
||||
@@ -101,7 +101,7 @@ A widget's lifecycle has 3 main phases:
|
||||
|
||||
* creation and initialization of the widget instance
|
||||
|
||||
.. function:: openerp.Widget.init(parent)
|
||||
.. function:: Widget.init(parent)
|
||||
|
||||
initialization method of widgets, synchronous, can be overridden to
|
||||
take more parameters from the widget's creator/parent
|
||||
@@ -109,26 +109,26 @@ A widget's lifecycle has 3 main phases:
|
||||
:param parent: the new widget's parent, used to handle automatic
|
||||
destruction and event propagation. Can be ``null`` for
|
||||
the widget to have no parent.
|
||||
:type parent: :class:`~openerp.Widget`
|
||||
:type parent: :class:`~Widget`
|
||||
|
||||
* DOM injection and startup, this is done by calling one of:
|
||||
|
||||
.. function:: openerp.Widget.appendTo(element)
|
||||
.. function:: Widget.appendTo(element)
|
||||
|
||||
Renders the widget and inserts it as the last child of the target, uses
|
||||
`.appendTo()`_
|
||||
|
||||
.. function:: openerp.Widget.prependTo(element)
|
||||
.. function:: Widget.prependTo(element)
|
||||
|
||||
Renders the widget and inserts it as the first child of the target, uses
|
||||
`.prependTo()`_
|
||||
|
||||
.. function:: openerp.Widget.insertAfter(element)
|
||||
.. function:: Widget.insertAfter(element)
|
||||
|
||||
Renders the widget and inserts it as the preceding sibling of the target,
|
||||
uses `.insertAfter()`_
|
||||
|
||||
.. function:: openerp.Widget.insertBefore(element)
|
||||
.. function:: Widget.insertBefore(element)
|
||||
|
||||
Renders the widget and inserts it as the following sibling of the target,
|
||||
uses `.insertBefore()`_
|
||||
@@ -138,12 +138,12 @@ A widget's lifecycle has 3 main phases:
|
||||
and are charged with three tasks:
|
||||
|
||||
* rendering the widget's root element via
|
||||
:func:`~openerp.Widget.renderElement`
|
||||
:func:`~Widget.renderElement`
|
||||
* inserting the widget's root element in the DOM using whichever jQuery
|
||||
method they match
|
||||
* starting the widget, and returning the result of starting it
|
||||
|
||||
.. function:: openerp.Widget.start()
|
||||
.. function:: Widget.start()
|
||||
|
||||
asynchronous startup of the widget once it's been injected in the DOM,
|
||||
generally used to perform asynchronous RPC calls to fetch whatever
|
||||
@@ -152,7 +152,7 @@ A widget's lifecycle has 3 main phases:
|
||||
Must return a deferred_ to indicate when its work is done.
|
||||
|
||||
A widget is *not guaranteed* to work correctly until its
|
||||
:func:`~openerp.Widget.start` method has finished executing. The
|
||||
:func:`~Widget.start` method has finished executing. The
|
||||
widget's parent/creator must wait for a widget to be fully started
|
||||
before interacting with it
|
||||
|
||||
@@ -160,7 +160,7 @@ A widget's lifecycle has 3 main phases:
|
||||
|
||||
* widget destruction and cleanup
|
||||
|
||||
.. function:: openerp.Widget.destroy()
|
||||
.. function:: Widget.destroy()
|
||||
|
||||
destroys the widget's children, unbinds its events and removes its root
|
||||
from the DOM. Automatically called when the widget's parent is destroyed,
|
||||
@@ -171,7 +171,7 @@ A widget's lifecycle has 3 main phases:
|
||||
|
||||
Related to widget destruction is an important utility method:
|
||||
|
||||
.. function:: openerp.Widget.alive(deferred[, reject=false])
|
||||
.. function:: Widget.alive(deferred[, reject=false])
|
||||
|
||||
A significant issue with RPC and destruction is that an RPC call may take
|
||||
a long time to execute and return while a widget is being destroyed or
|
||||
@@ -180,7 +180,7 @@ Related to widget destruction is an important utility method:
|
||||
|
||||
This is a frequent source of errors or strange behaviors.
|
||||
|
||||
:func:`~openerp.Widget.alive` can be used to wrap an RPC call,
|
||||
:func:`~Widget.alive` can be used to wrap an RPC call,
|
||||
ensuring that whatever operations should be executed when the call ends
|
||||
are only executed if the widget is still alive::
|
||||
|
||||
@@ -199,7 +199,7 @@ Related to widget destruction is an important utility method:
|
||||
``true``, the deferred_ will be rejected instead.
|
||||
:returns: deferred_ object
|
||||
|
||||
.. function:: openerp.Widget.isDestroyed()
|
||||
.. function:: Widget.isDestroyed()
|
||||
|
||||
:returns: ``true`` if the widget is being or has been destroyed, ``false``
|
||||
otherwise
|
||||
@@ -210,7 +210,7 @@ Accessing DOM content
|
||||
Because a widget is only responsible for the content below its DOM root, there
|
||||
is a shortcut for selecting sub-sections of a widget's DOM:
|
||||
|
||||
.. function:: openerp.Widget.$(selector)
|
||||
.. function:: Widget.$(selector)
|
||||
|
||||
Applies the CSS selector specified as parameter to the widget's
|
||||
DOM root::
|
||||
@@ -229,7 +229,7 @@ Because a widget is only responsible for the content below its DOM root, there
|
||||
Resetting the DOM root
|
||||
''''''''''''''''''''''
|
||||
|
||||
.. function:: openerp.Widget.setElement(element)
|
||||
.. function:: Widget.setElement(element)
|
||||
|
||||
Re-sets the widget's DOM root to the provided element, also
|
||||
handles re-setting the various aliases of the DOM root as well as
|
||||
@@ -247,9 +247,9 @@ DOM events handling
|
||||
A widget will generally need to respond to user action within its
|
||||
section of the page. This entails binding events to DOM elements.
|
||||
|
||||
To this end, :class:`~openerp.Widget` provides a shortcut:
|
||||
To this end, :class:`~Widget` provides a shortcut:
|
||||
|
||||
.. attribute:: openerp.Widget.events
|
||||
.. attribute:: Widget.events
|
||||
|
||||
Events are a mapping of an event selector (an event name and an optional
|
||||
CSS selector separated by a space) to a callback. The callback can
|
||||
@@ -269,23 +269,23 @@ To this end, :class:`~openerp.Widget` provides a shortcut:
|
||||
(only an event name is specified), the event will be set directly on the
|
||||
widget's DOM root.
|
||||
|
||||
.. function:: openerp.Widget.delegateEvents
|
||||
.. function:: Widget.delegateEvents
|
||||
|
||||
This method is in charge of binding :attr:`~openerp.Widget.events` to the
|
||||
This method is in charge of binding :attr:`~Widget.events` to the
|
||||
DOM. It is automatically called after setting the widget's DOM root.
|
||||
|
||||
It can be overridden to set up more complex events than the
|
||||
:attr:`~openerp.Widget.events` map allows, but the parent should always be
|
||||
called (or :attr:`~openerp.Widget.events` won't be handled correctly).
|
||||
:attr:`~Widget.events` map allows, but the parent should always be
|
||||
called (or :attr:`~Widget.events` won't be handled correctly).
|
||||
|
||||
.. function:: openerp.Widget.undelegateEvents
|
||||
.. function:: Widget.undelegateEvents
|
||||
|
||||
This method is in charge of unbinding :attr:`~openerp.Widget.events` from
|
||||
This method is in charge of unbinding :attr:`~Widget.events` from
|
||||
the DOM root when the widget is destroyed or the DOM root is reset, in
|
||||
order to avoid leaving "phantom" events.
|
||||
|
||||
It should be overridden to un-set any event set in an override of
|
||||
:func:`~openerp.Widget.delegateEvents`.
|
||||
:func:`~Widget.delegateEvents`.
|
||||
|
||||
.. note:: this behavior should be compatible with `Backbone's
|
||||
delegateEvents`_, apart from not accepting any argument.
|
||||
@@ -293,12 +293,12 @@ To this end, :class:`~openerp.Widget` provides a shortcut:
|
||||
Subclassing Widget
|
||||
------------------
|
||||
|
||||
:class:`~openerp.Widget` is subclassed in the standard manner (via the
|
||||
:func:`~openerp.Class.extend` method), and provides a number of
|
||||
:class:`~Widget` is subclassed in the standard manner (via the
|
||||
:func:`~Class.extend` method), and provides a number of
|
||||
abstract properties and concrete methods (which you may or may not want to
|
||||
override). Creating a subclass looks like this::
|
||||
|
||||
var MyWidget = openerp.Widget.extend({
|
||||
var MyWidget = Widget.extend({
|
||||
// QWeb template to use when rendering the object
|
||||
template: "MyQWebTemplate",
|
||||
events: {
|
||||
@@ -332,14 +332,14 @@ The new class can then be used in the following manner::
|
||||
my_widget.appendTo(".some-div");
|
||||
|
||||
After these two lines have executed (and any promise returned by
|
||||
:func:`~openerp.Widget.appendTo` has been resolved if needed), the widget is
|
||||
:func:`~Widget.appendTo` has been resolved if needed), the widget is
|
||||
ready to be used.
|
||||
|
||||
.. note:: the insertion methods will start the widget themselves, and will
|
||||
return the result of :func:`~openerp.Widget.start()`.
|
||||
return the result of :func:`~Widget.start()`.
|
||||
|
||||
If for some reason you do not want to call these methods, you will
|
||||
have to first call :func:`~openerp.Widget.render()` on the
|
||||
have to first call :func:`~Widget.render()` on the
|
||||
widget, then insert it into your DOM and start it.
|
||||
|
||||
If the widget is not needed anymore (because it's transient), simply terminate
|
||||
@@ -373,14 +373,14 @@ Development Guidelines
|
||||
restricted to a given component's scope. Unfiltered selections such as
|
||||
``$(selector)`` or ``document.querySelectorAll(selector)`` will generally
|
||||
lead to unintended or incorrect behavior. Odoo Web's
|
||||
:class:`~openerp.web.Widget` has an attribute providing its DOM root
|
||||
(:attr:`~openerp.web.Widget.$el`), and a shortcut to select nodes directly
|
||||
(:func:`~openerp.web.Widget.$`).
|
||||
:class:`~Widget` has an attribute providing its DOM root
|
||||
(:attr:`~Widget.$el`), and a shortcut to select nodes directly
|
||||
(:func:`~Widget.$`).
|
||||
* More generally, never assume your components own or controls anything beyond
|
||||
its own personal :attr:`~openerp.web.Widget.$el`
|
||||
its own personal :attr:`~Widget.$el`
|
||||
* html templating/rendering should use QWeb unless absolutely trivial.
|
||||
* All interactive components (components displaying information to the screen
|
||||
or intercepting DOM events) must inherit from :class:`~openerp.web.Widget`
|
||||
or intercepting DOM events) must inherit from :class:`~Widget`
|
||||
and correctly implement and use its API and life cycle.
|
||||
|
||||
.. _.appendTo():
|
||||
@@ -426,11 +426,11 @@ High-level API: calling into Odoo models
|
||||
-------------------------------------------
|
||||
|
||||
Access to Odoo object methods (made available through XML-RPC from the server)
|
||||
is done via :class:`openerp.Model`. It maps onto the Odoo server objects via
|
||||
two primary methods, :func:`~openerp.Model.call` and
|
||||
:func:`~openerp.Model.query`.
|
||||
is done via :class:`Model` (exported in ``web.Model``). It maps onto the Odoo server objects via
|
||||
two primary methods, :func:`~Model.call` and
|
||||
:func:`~Model.query`.
|
||||
|
||||
:func:`~openerp.Model.call` is a direct mapping to the corresponding method of
|
||||
:func:`~Model.call` is a direct mapping to the corresponding method of
|
||||
the Odoo server object. Its usage is similar to that of the Odoo Model API,
|
||||
with three differences:
|
||||
|
||||
@@ -446,14 +446,14 @@ with three differences:
|
||||
* No notion of pooler, the model proxy is instantiated where needed,
|
||||
not fetched from an other (somewhat global) object::
|
||||
|
||||
var Users = new openerp.Model('res.users');
|
||||
var Users = new Model('res.users');
|
||||
|
||||
Users.call('change_password', ['oldpassword', 'newpassword'],
|
||||
{context: some_context}).then(function (result) {
|
||||
// do something with change_password result
|
||||
});
|
||||
|
||||
:func:`~openerp.Model.query` is a shortcut for a builder-style
|
||||
:func:`~Model.query` is a shortcut for a builder-style
|
||||
interface to searches (``search`` + ``read`` in Odoo RPC terms). It
|
||||
returns a :class:`~openerp.web.Query` object which is immutable but
|
||||
allows building new :class:`~openerp.web.Query` instances from the
|
||||
@@ -474,26 +474,26 @@ RPC call every time they are called.
|
||||
For that reason, it's actually possible to keep "intermediate" queries
|
||||
around and use them differently/add new specifications on them.
|
||||
|
||||
.. class:: openerp.Model(name)
|
||||
.. class:: Model(name)
|
||||
|
||||
.. attribute:: openerp.Model.name
|
||||
.. attribute:: Model.name
|
||||
|
||||
name of the OpenERP model this object is bound to
|
||||
name of the model this object is bound to
|
||||
|
||||
.. function:: openerp.Model.call(method[, args][, kwargs])
|
||||
.. function:: Model.call(method[, args][, kwargs])
|
||||
|
||||
Calls the ``method`` method of the current model, with the
|
||||
provided positional and keyword arguments.
|
||||
|
||||
:param String method: method to call over rpc on the
|
||||
:attr:`~openerp.Model.name`
|
||||
:attr:`~Model.name`
|
||||
:param Array<> args: positional arguments to pass to the
|
||||
method, optional
|
||||
:param Object<> kwargs: keyword arguments to pass to the
|
||||
method, optional
|
||||
:rtype: Deferred<>
|
||||
|
||||
.. function:: openerp.Model.query(fields)
|
||||
.. function:: Model.query(fields)
|
||||
|
||||
:param Array<String> fields: list of fields to fetch during
|
||||
the search
|
||||
@@ -652,7 +652,7 @@ an array of :class:`~openerp.web.QueryGroup`:
|
||||
|
||||
.. function:: openerp.web.QueryGroup.query([fields...])
|
||||
|
||||
equivalent to :func:`openerp.web.Model.query` but pre-filtered to
|
||||
equivalent to :func:`Model.query` but pre-filtered to
|
||||
only include the records within this group. Returns a
|
||||
:class:`~openerp.web.Query` which can be further manipulated as
|
||||
usual.
|
||||
@@ -670,8 +670,8 @@ While the previous section is great for calling core OpenERP code
|
||||
Odoo Web.
|
||||
|
||||
For this, a lower-level API exists on on
|
||||
:class:`~openerp.web.Session` objects (usually available through
|
||||
``openerp.session``): the ``rpc`` method.
|
||||
:class:`~Session` objects (the class is exported in ``web.Session``, but
|
||||
an instance isusually available through ``web.session``): the ``rpc`` method.
|
||||
|
||||
This method simply takes an absolute path (the absolute URL of the JSON
|
||||
:ref:`route <reference/http/routing>` to call) and a mapping of attributes to
|
||||
@@ -681,7 +681,7 @@ fetches the return value of the Python methods, converted to JSON.
|
||||
For instance, to call the ``resequence`` of the
|
||||
:class:`~web.controllers.main.DataSet` controller::
|
||||
|
||||
openerp.session.rpc('/web/dataset/resequence', {
|
||||
session.rpc('/web/dataset/resequence', {
|
||||
model: some_model,
|
||||
ids: array_of_ids,
|
||||
offset: 42
|
||||
@@ -696,6 +696,122 @@ For instance, to call the ``resequence`` of the
|
||||
Web Client
|
||||
==========
|
||||
|
||||
Javascript module system overview
|
||||
---------------------------------
|
||||
|
||||
A new module system (inspired from requirejs) has now been deployed.
|
||||
It has many advantages over the Odoo version 8 system.
|
||||
|
||||
* loading order: dependencies are guaranteed to be loaded first, even if
|
||||
files are not loaded in the correct order in the bundle files.
|
||||
* easier to split a file into smaller logical units.
|
||||
* no global variables: easier to reason.
|
||||
* it is possible to examine every dependencies and dependants. This
|
||||
makes refactoring much simpler, and less risky.
|
||||
|
||||
It has also some disadvantages:
|
||||
|
||||
* files are required to use the module system if they want to interact
|
||||
with odoo, since the various objects are only available in the module
|
||||
system, and not in global variables
|
||||
* circular dependencies are not supported. It makes sense, but it means
|
||||
that one needs to be careful.
|
||||
|
||||
This is obviously a very large change and will require everyone to
|
||||
adopt new habits. For example, the variable openerp does not exist
|
||||
anymore. The new way of doing things is to import explicitely the module
|
||||
you need, and declaring explicitely the objects you export. Here is a
|
||||
simple example::
|
||||
|
||||
odoo.define('addon_name.service', function (require) {
|
||||
var utils = require('web.utils');
|
||||
var Model = require('web.Model');
|
||||
|
||||
// do things with utils and Model
|
||||
var something_useful = 15;
|
||||
return {
|
||||
something_useful: something_useful,
|
||||
};
|
||||
});
|
||||
|
||||
This snippet shows a module named ``addon_name.service``. It is defined
|
||||
with the ``odoo.define`` function. ``odoo.define`` takes a name and a
|
||||
function for arguments:
|
||||
|
||||
* The name is the concatenation of the name of the addon it is defined in
|
||||
and a name describing its purpose.
|
||||
* The function is the place where the javascript module is actually
|
||||
defined. It takes a function ``require`` as first argument, and
|
||||
returns something (or not, depending if it needs to export something).
|
||||
The ``require`` function is used to get a handle on the dependencies.
|
||||
In this case, it gives a handle on two javascript modules from the
|
||||
``web`` addon, namely ``web.utils`` and ``web.Model``.
|
||||
|
||||
The idea is that you define what you need to import (by using the
|
||||
``require`` function) and declare what you export (by returning
|
||||
something). The web client will then make sure that your code is loaded
|
||||
properly.
|
||||
|
||||
Modules are contained in a file, but a file can define several modules
|
||||
(however, it is better to keep them in separate files).
|
||||
|
||||
|
||||
Web client structure
|
||||
--------------------
|
||||
|
||||
The web client files have been refactored into smaller and simpler files.
|
||||
Here is a description of the current file structure:
|
||||
|
||||
* the ``framework/`` folder contains all basic low level modules. The
|
||||
modules here are supposed to be generic. Some of them are:
|
||||
|
||||
* ``web.ajax`` implements rpc calls
|
||||
* ``web.core`` is a generic modules. It exports various useful
|
||||
objects and functions, such as ``qweb``, ``_t`` or the main bus.
|
||||
* ``web.Widget`` contains the widget class
|
||||
* ``web.Model`` is an abstraction over ``web.ajax`` to make
|
||||
calls to the server model methods
|
||||
* ``web.session`` is the former ``openerp.session``
|
||||
* ``web.utils`` for useful code snippets
|
||||
* ``web.time`` for every time-related generic functions
|
||||
* the ``views/`` folder contains all view definitions
|
||||
* ``widgets/`` is for standalone widgets
|
||||
|
||||
The ``js/`` folder also contains some important files:
|
||||
|
||||
* ``action_manager.js`` is the ActionManager class
|
||||
* ``boot.js`` is the file actually implementing the module system
|
||||
* ``menu.js`` is the definition of the top menu
|
||||
* ``web_client.js`` is for the root widget WebClient
|
||||
* ``view_manager.js`` contains the ViewManager
|
||||
|
||||
The two other files are ``tour.js`` for the tours and ``compatibility.js``.
|
||||
The latter file is a compatibility layer bridging the old system to the
|
||||
new module system. This is where every module names are exported to the
|
||||
global variable ``openerp``. In theory, our addons should work without
|
||||
ever using the variable ``openerp``, and the compatibility module can be
|
||||
disabled safely.
|
||||
|
||||
Javascript conventions
|
||||
----------------------
|
||||
|
||||
Here are some basic conventions for the javascript code:
|
||||
|
||||
* declare all your dependencies at the top of the module. Also, they
|
||||
should be sorted alphabetically by module name. This makes it
|
||||
easier to understand your module.
|
||||
* declare all exports at the end.
|
||||
* add the ``use strict`` statement at the beginning of every module
|
||||
* always name your module properly: ``addon_name.description``.
|
||||
* use capital letters for classes (for example, ``ActionManager`` is
|
||||
defined in the module ``web.ActionManager``), and lowercase for
|
||||
everything else (for example, ``ajax`` is defined in ``web.ajax``).
|
||||
* declare one module per file
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Testing in Odoo Web Client
|
||||
==========================
|
||||
|
||||
|
||||
@@ -516,13 +516,13 @@ The javascript QWeb implementation provides a few debugging hooks:
|
||||
Helpers
|
||||
-------
|
||||
|
||||
.. js:attribute:: openerp.qweb
|
||||
.. js:attribute:: core.qweb
|
||||
|
||||
An instance of :js:class:`QWeb2.Engine` with all module-defined template
|
||||
(core is the ``web.core`` module) An instance of :js:class:`QWeb2.Engine` with all module-defined template
|
||||
files loaded, and references to standard helper objects ``_``
|
||||
(underscore), ``_t`` (translation function) and JSON_.
|
||||
|
||||
:js:func:`openerp.qweb.render <QWeb2.Engine.render>` can be used to
|
||||
:js:func:`core.qweb.render <QWeb2.Engine.render>` can be used to
|
||||
easily render basic module templates
|
||||
|
||||
API
|
||||
@@ -533,9 +533,9 @@ API
|
||||
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.
|
||||
OpenERP Web instantiates one for the user in the core module, and
|
||||
exports it to ``core.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".
|
||||
|
||||
|
||||
Reference in New Issue
Block a user