[FIX] doc: rename and re-include 'presentation'
bzr revid: xmo@openerp.com-20121212165739-5u1880yhb4gq4pfl
This commit is contained in:
parent
e9b946d243
commit
26cfe040cb
|
@ -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.
|
|
@ -14,11 +14,14 @@ Contents:
|
|||
module
|
||||
widget
|
||||
|
||||
|
||||
async
|
||||
rpc
|
||||
qweb
|
||||
client_action
|
||||
|
||||
guidelines
|
||||
|
||||
testing
|
||||
|
||||
search_view
|
||||
|
|
|
@ -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/
|
|
@ -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
|
||||
---------------------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue