[FIX] doc: rename and re-include 'presentation'

bzr revid: xmo@openerp.com-20121212165739-5u1880yhb4gq4pfl
This commit is contained in:
Xavier Morel 2012-12-12 17:57:39 +01:00
parent e9b946d243
commit 26cfe040cb
5 changed files with 100 additions and 49 deletions

View File

@ -0,0 +1,77 @@
Guidelines and Recommendations
==============================
Web Module Recommendations
--------------------------
Identifiers (``id`` attribute) should be avoided
''''''''''''''''''''''''''''''''''''''''''''''''
In generic applications and modules, ``@id`` limits the reusabily of
components and tends to make code more brittle.
Just about all the time, they can be replaced with nothing, with
classes or with keeping a reference to a DOM node or a jQuery element
around.
.. note::
If it is *absolutely necessary* to have an ``@id`` (because a
third-party library requires one and can't take a DOM element), it
should be generated with `_.uniqueId
<http://underscorejs.org/#uniqueId>`_ or some other similar
method.
Avoid predictable/common CSS class names
''''''''''''''''''''''''''''''''''''''''
Class names such as "content" or "navigation" might match the desired
meaning/semantics, but it is likely an other developer will have the
same need, creating a naming conflict and unintended behavior. Generic
class names should be prefixed with e.g. the name of the component
they belong to (creating "informal" namespaces, much as in C or
Objective-C)
Global selectors should be avoided
''''''''''''''''''''''''''''''''''
Because a component may be used several times in a single page (an
example in OpenERP is dashboards), queries should be restricted to a
given component's scope. Unfiltered selections such as ``$(selector)``
or ``document.querySelectorAll(selector)`` will generally lead to
unintended or incorrect behavior.
OpenERP Web's :js:class:`~openerp.web.Widget` has an attribute
providing its DOM root :js:attr:`Widget.$el <openerp.web.Widget.$el>`,
and a shortcut to select nodes directly :js:attr:`Widget.$
<openerp.web.Widget.$>`.
More generally, never assume your components own or controls anything
beyond its own personal DOM.
Understand deferreds
''''''''''''''''''''
Deferreds, promises, futures, …
Known under many names, these objects are essential to and (in OpenERP
Web) widely used for making :doc:`asynchronous javascript operations
<async>` palatable and understandable.
OpenERP Web guidelines
----------------------
* HTML templating/rendering should use :doc:`qweb` unless absolutely
trivial.
* All interactive components (components displaying information to the
screen or intercepting DOM events) must inherit from
:class:`~openerp.web.Widget` and correctly implement and use its API
and lifecycle.
* All css classes must be prefixed with *oe_* .
* Asynchronous functions (functions which call :ref:`session.rpc
<rpc_rpc>` directly or indirectly at the very least) *must* return
deferreds, so that callers of overriders can correctly synchronize
with them.

View File

@ -14,11 +14,14 @@ Contents:
module
widget
async
rpc
qweb
client_action
guidelines
testing
search_view

View File

@ -1,42 +0,0 @@
Presentation
============
Prerequisites
-------------
Prerequisites to code addons for the OpenERP Web Client:
- HTML5
- CSS
- Javascript (Ecmascript 5)
- jQuery
Once you know all this, that's only the beginning. Most usages of Javascript/jQuery are small hacks to make a web page nicer. The OpenERP Client Web is different: it's a web application, not a web site. It doesn't have multiple pages generated by a server side code. Only one unique empty page is loaded and all the html is generated by Javascript code, the page is never reloaded. If you never developed that kind of application you still have lot of good practices to learn.
Generic Guidelines
------------------
First, here are some generic recommandations about web 2.0 applications:
* **Do not use ids**. Html ids are evil, the key anti-feature that makes your components non-reusable. You want to identify a dom part? Save a jQuery object over that dom element. If you really need to use ids, use _.uniqueId(), but 99% of the time you don't need to, classes are sufficient.
* **Do not use predictable css class names** like "content" or "navigation", ten other developers will have the same idea than you and there will be clashes. A simple way to avoid this is to use prefixes. For example, if you need a css class for the button named "new" that is contained in the form view which is itself contained in the OpenERP application, name it "oe-form-view-new-button".
* **Do not use global selectors** like *$(".my-class")*, you never know if your component will be instantiated multiple times. Limit the selector with a context, like *$(".my-class", this.$el)*.
* As a general advice, **Never assume you own the page**. When you create a component, it is never unique and is always surrounded by a bunch of crazy html. You have to do with it.
* **Learn how to use jQuery's deferreds** [1]_. That concept may seem over-complicated, but the experience tell us that it is nearly impossible to create big-size javascript applications without that.
OpenERP guidelines
------------------
More recommendations related to the specific case of the OpenERP Web Client:
* The code should conform to EcmasScript 5 without the "use strict" mode as we support IE9.
* Your components should inherit from the *Widget* class. And use *Widget* 's methods (*appendTo*, *replace*,...) to insert your component and its content into the dom.
* Use QWeb templates for html rendering.
* All css classes should have the prefix *oe_* .
* Functions that call rpc() should return a deferred, even if it calls it indirectly. So a function that calls a function that calls a function that calls rpc() should return a deferred too.
.. [1] http://api.jquery.com/category/deferred-object/

View File

@ -240,6 +240,8 @@ regular query for records):
The result of a (successful) :js:func:`~openerp.web.Query.group_by` is
an array of :js:class:`~openerp.web.QueryGroup`.
.. _rpc_rpc:
Low-level API: RPC calls to Python side
---------------------------------------

View File

@ -1,6 +1,8 @@
Widget
======
.. js:class:: openerp.web.Widget
This is the base class for all visual components. It corresponds to an MVC
view. It provides a number of services to handle a section of a page:
@ -15,19 +17,19 @@ view. It provides a number of services to handle a section of a page:
be anything the corresponding jQuery method accepts (generally selectors,
DOM nodes and jQuery objects):
:js:func:`~openerp.base.Widget.appendTo`
:js:func:`~openerp.web.Widget.appendTo`
Renders the widget and inserts it as the last child of the target, uses
`.appendTo()`_
:js:func:`~openerp.base.Widget.prependTo`
:js:func:`~openerp.web.Widget.prependTo`
Renders the widget and inserts it as the first child of the target, uses
`.prependTo()`_
:js:func:`~openerp.base.Widget.insertAfter`
:js:func:`~openerp.web.Widget.insertAfter`
Renders the widget and inserts it as the preceding sibling of the target,
uses `.insertAfter()`_
:js:func:`~openerp.base.Widget.insertBefore`
:js:func:`~openerp.web.Widget.insertBefore`
Renders the widget and inserts it as the following sibling of the target,
uses `.insertBefore()`_
@ -41,7 +43,7 @@ DOM Root
A :js:class:`~openerp.web.Widget` is responsible for a section of the
page materialized by the DOM root of the widget. The DOM root is
available via the :js:attr:`~openerp.web.Widget.el` and
:js:attr:`~openerp.web.Widget.$element` attributes, which are
:js:attr:`~openerp.web.Widget.$el` attributes, which are
respectively the raw DOM Element and the jQuery wrapper around the DOM
element.
@ -123,7 +125,7 @@ DOM:
.. code-block:: javascript
this.$element.find(selector);
this.$el.find(selector);
:param String selector: CSS selector
:returns: jQuery object
@ -159,7 +161,16 @@ To this end, :js:class:`~openerp.web.Widget` provides an shortcut:
Events are a mapping of ``event selector`` (an event name and a
CSS selector separated by a space) to a callback. The callback can
be either a method name in the widget or a function. In either
case, the ``this`` will be set to the widget.
case, the ``this`` will be set to the widget:
.. code-block:: javascript
events: {
'click p.oe_some_class a': 'some_method',
'change input': function (e) {
e.stopPropagation();
}
},
The selector is used for jQuery's `event delegation`_, the
callback will only be triggered for descendants of the DOM root