[REM] old doc

bzr revid: xmo@openerp.com-20121002134604-w6xbkg7sqitd96db
This commit is contained in:
Xavier Morel 2012-10-02 15:46:04 +02:00
parent c28dfb19e1
commit c8dead4f60
8 changed files with 0 additions and 1418 deletions

View File

@ -1,449 +0,0 @@
Developing OpenERP Web Addons
=============================
An OpenERP Web addon is simply a Python package with an openerp
descriptor (a ``__openerp__.py`` file) which follows a few structural
and namespacing rules.
Structure
---------
.. literalinclude:: addon-structure.txt
``__openerp__.py``
The addon's descriptor, contains the following information:
``name: str``
The addon name, in plain, readable english
``version: str``
The addon version, following `Semantic Versioning`_ rules
``depends: [str]``
A list of addons this addon needs to work correctly. ``base`` is
an implied dependency if the list is empty.
``css: [str]``
An ordered list of CSS files this addon provides and needs. The
file paths are relative to the addon's root. Because the Web
Client *may* perform concatenations and other various
optimizations on CSS files, the order is important.
``js: [str]``
An ordered list of Javascript files this addon provides and needs
(including dependencies files). As with CSS files, the order is
important as the Web Client *may* perform contatenations and
minimizations of files.
``active: bool``
Whether this addon should be enabled by default any time it is
found, or whether it will be enabled through other means (on a
by-need or by-installation basis for instance).
``controllers/``
All of the Python controllers and JSON-RPC endpoints.
``static/``
The static files directory, may be served via a separate web server.
``static/lib/``
Third-party libraries used by the addon.
``static/src/{css,js,img,xml}``
Location for (respectively) the addon's static CSS files, its JS
files, its various image resources as well as the template files
``static/test``
Javascript tests files
``test/``
The directories in which all tests for the addon are located.
Some of these are guidelines (and not enforced by code), but it's
suggested that these be followed. Code which does not fit into these
categories can go wherever deemed suitable.
Namespacing
-----------
Python
++++++
Because addons are also Python packages, they're inherently namespaced
and nothing special needs to be done on that front.
JavaScript
++++++++++
The JavaScript side of an addon has to live in the namespace
``openerp.$addon_name``. For instance, everything created by the addon
``base`` lives in ``openerp.base``.
The root namespace of the addon is a function which takes a single
parameter ``openerp``, which is an OpenERP client instance. Objects
(as well as functions, registry instances, etc...) should be added on
the correct namespace on that object.
The root function will be called by the OpenERP Web client when
initializing the addon.
.. code-block:: javascript
// root namespace of the openerp.example addon
/** @namespace */
openerp.example = function (openerp) {
// basic initialization code (e.g. templates loading)
openerp.example.SomeClass = openerp.base.Class.extend(
/** @lends openerp.example.SomeClass# */{
/**
* Description for SomeClass's constructor here
*
* @constructs
*/
init: function () {
// SomeClass initialization code
}
// rest of SomeClass
});
// access an object in an other addon namespace to replace it
openerp.base.SearchView = openerp.base.SearchView.extend({
init: function () {
this._super.apply(this, arguments);
console.log('Search view initialized');
}
});
}
Creating new standard roles
---------------------------
Views
+++++
Views are the standard high-level component in OpenERP. A view type corresponds
to a way to display a set of data (coming from an OpenERP model).
In OpenERP Web, views are standard objects registered against a dedicated
object registry, so the :js:class:`~openerp.base.ViewManager` knows where to
find and how to call them.
Although not mandatory, it is recommended that views inherit from
:js:class:`openerp.base.View`, which provides a view useful services to its
children.
Registering a view
~~~~~~~~~~~~~~~~~~
This is the first task to perform when creating a view, and the simplest by
far: simply call ``openerp.base.views.add(name, object_path)`` to register
the object of path ``object_path`` as the view for the view name ``name``.
The view name is the name you gave to your new view in the OpenERP server.
From that point onwards, OpenERP Web will be able to find your object and
instantiate it.
Standard view behaviors
~~~~~~~~~~~~~~~~~~~~~~~
In the normal OpenERP Web flow, views have to implement a number of methods so
view managers can correctly communicate with them:
``start()``
This method will always be called after creating the view (via its
constructor), but not necessarily immediately.
It is called with no arguments and should handle the heavy setup work,
including remote call (to load the view's setup data from the server via
e.g. ``fields_view_get``, for instance).
``start`` should return a `promise object`_ which *must* be resolved when
the view's setup is completed. This promise is used by view managers to
know when they can start interacting with the view.
``do_hide()``
Called by the view manager when it wants to replace this view by an other
one, but wants to keep this view around to re-activate it later.
Should put the view in some sort of hibernation mode, and *must* hide its
DOM elements.
``do_show()``
Called when the view manager wants to re-display the view after having
hidden it. The view should refresh its data display upon receiving this
notification
``do_search(domain: Array, context: Object, group_by: Array)``
If the view is searchable, this method is called to notify it of a search
against it.
It should use the provided query data to perform a search and refresh its
internal content (and display).
All views are searchable by default, but they can be made non-searchable
by setting the property ``searchable`` to ``false``.
This can be done either on the view class itself (at the same level as
defining e.g. the ``start`` method) or at the instance level (in the
class's ``init``), though you should generally set it on the class.
Frequent development tasks
--------------------------
There are a number of tasks which OpenERP Web developers do or will need to
perform quite regularly. To make these easier, we have written a few guides
to help you get started:
.. toctree::
:maxdepth: 1
guides/client-action
guides/sidebar-protocol
Translations
------------
OpenERP Web should provide most of the tools needed to correctly translate your
addons via the tool of your choice (OpenERP itself uses `Launchpad's own
translation tool`_.
Making strings translatable
+++++++++++++++++++++++++++
QWeb
~~~~
QWeb automatically marks all text nodes (any text which is not in an XML
attribute and not part of an XML tag) as translatable, and handles the
replacement for you. There is nothing special to do to mark template text as
translatable
JavaScript
~~~~~~~~~~
OpenERP Web provides two functions to translate human-readable strings in
javascript code. These functions should be "imported" in your module by
aliasing them to their bare name:
.. code-block:: javascript
var _t = openerp.web._t,
_tl = openerp.web._tl;
importing those functions under any other name is not guaranteed to work.
.. note:: only import them if necessary, and only the necessary one(s), no need
to clutter your module's namespace for nothing
.. js:function:: openerp.web._t(s)
Base translation function, eager, works much like :manpage:`gettext(3)`
:type s: String
:rtype: String
.. js:function:: openerp.web._lt(s)
Lazy equivalent to :js:func:`~openerp.web._t`, this function will postpone
fetching the translation to its argument until the last possible moment.
To use in contexts evaluated before the translation database can be
fetched, usually your module's toplevel and the attributes of classes
defined in it (class attributes, not instance attributes set in the
constructor).
:type s: String
:rtype: LazyString
Text formatting & translations
""""""""""""""""""""""""""""""
A difficulty when translating is integrating data (from the code) into the
translated string. In OpenERP Web addons, this should be done by wrapping the
text to translate in an :manpage:`sprintf(3)` call. For OpenERP Web,
:manpage:`sprintf(3)` is provided by `underscore.string
<http://epeli.github.com/underscore.string/>`_.
As much as possible, you should use the "named argument" form of sprintf:
.. code-block:: javascript
var translated_string = _.str.sprintf(
_t("[%(first_record)d to %(last_record)d] of %(records_count)d"), {
first_record: first + 1,
last_record: last,
records_count: total
}));
named arguments make the string to translate much clearer for translators, and
allows them to "move" sections around based on the requirements of their
language (not all language order text like english).
Named arguments are specified using the following pattern: ``%($name)$type``
where
``$name``
the name of the argument, this is the key in the object/dictionary provided
as second parameter to ``sprintf``
``$type``
a type/format specifier, `see the list for all possible types
<http://www.diveintojavascript.com/projects/javascript-sprintf>`_.
.. note:: positional arguments are acceptable if the translated string has
*a single* argument and its content is easy to guess from the text
around it. Named arguments should still be preferred.
.. warning:: you should *never* use string concatenation as it robs the
translator of context and make result in a completely incorrect
translation
Extracting strings
~~~~~~~~~~~~~~~~~~
.. program:: gen_translations.sh
Once strings have been marked for translation, they need to be extracted into
:abbr:`POT (Portable Object Template)` files, from which most translation tools
can build a database.
This can be done via the provided :program:`gen_translations.sh`.
It can be called either as :option:`gen_translations.sh -a` or by providing
two parameters, a path to the addons and the complete path in which to put the
extracted POT file.
.. option:: -a
Extracts translations from all standard OpenERP Web addons (addons bundled
with OpenERP Web itself) and puts the extracted templates into the right
directory for `Rosetta`_ to handle them
Utility behaviors
-----------------
JavaScript
++++++++++
* All javascript objects inheriting from
:js:class:`openerp.base.BasicConroller` will have all methods
starting with ``on_`` or ``do_`` bound to their ``this``. This means
they don't have to be manually bound (via ``_.bind`` or ``$.proxy``)
in order to be useable as bound event handlers (event handlers
keeping their object as ``this`` rather than taking whatever
``this`` object they were called with).
Beware that this is only valid for methods starting with ``do_`` and
``on_``, any other method will have to be bound manually.
.. _addons-testing:
Testing
-------
Python
++++++
OpenERP Web uses unittest2_ for its testing needs. We selected
unittest2 rather than unittest_ for the following reasons:
* autodiscovery_ (similar to nose, via the ``unit2``
CLI utility) and `pluggable test discovery`_.
* `new and improved assertions`_ (with improvements in type-specific
inequality reportings) including `pluggable custom types equality
assertions`_
* neveral new APIs, most notably `assertRaises context manager`_,
`cleanup function registration`_, `test skipping`_ and `class- and
module-level setup and teardown`_
* finally, unittest2 is a backport of Python 3's unittest. We might as
well get used to it.
To run tests on addons (from the root directory of OpenERP Web) is as
simple as typing ``PYTHONPATH=. unit2 discover -s addons`` [#]_. To
test an addon which does not live in the ``addons`` directory, simply
replace ``addons`` by the directory in which your own addon lives.
.. note:: unittest2 is entirely compatible with nose_ (or the
other way around). If you want to use nose as your test
runner (due to its addons for instance) you can simply install it
and run ``nosetests addons`` instead of the ``unit2`` command,
the result should be exactly the same.
Python
++++++
.. autoclass:: web.common.session.OpenERPSession
:members:
.. autoclass:: web.common.openerplib.main.Model
:members:
* Addons lifecycle (loading, execution, events, ...)
* Python-side
* JS-side
* Handling static files
* Overridding a Python controller (object?)
* Overridding a Javascript controller (object?)
* Extending templates
.. how do you handle deploying static files via e.g. a separate lighttpd?
* Python public APIs
* QWeb templates description?
* OpenERP Web modules (from OpenERP modules)
.. [#] the ``-s`` parameter tells ``unit2`` to start trying to
find tests in the provided directory (here we're testing
addons). However a side-effect of that is to set the
``PYTHONPATH`` there as well, so it will fail to find (and
import) ``openerpweb``.
The ``-t`` parameter lets us set the ``PYTHONPATH``
independently, but it doesn't accept multiple values and here
we really want to have both ``.`` and ``addons`` on the
``PYTHONPATH``.
The solution is to set the ``PYTHONPATH`` to ``.`` on start,
and the ``start-directory`` to ``addons``. This results in a
correct ``PYTHONPATH`` within ``unit2``.
.. _unittest:
http://docs.python.org/library/unittest.html
.. _unittest2:
http://www.voidspace.org.uk/python/articles/unittest2.shtml
.. _autodiscovery:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#test-discovery
.. _pluggable test discovery:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#load-tests
.. _new and improved assertions:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#new-assert-methods
.. _pluggable custom types equality assertions:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#add-new-type-specific-functions
.. _assertRaises context manager:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#assertraises
.. _cleanup function registration:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#cleanup-functions-with-addcleanup
.. _test skipping:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#test-skipping
.. _class- and module-level setup and teardown:
http://www.voidspace.org.uk/python/articles/unittest2.shtml#class-and-module-level-fixtures
.. _Semantic Versioning:
http://semver.org/
.. _nose:
http://somethingaboutorange.com/mrl/projects/nose/1.0.0/
.. _promise object:
http://api.jquery.com/deferred.promise/
.. _Rosetta:
.. _Launchpad's own translation tool:
https://help.launchpad.net/Translations

View File

@ -1,424 +0,0 @@
OpenERP Web Core and standard addons
====================================
* General organization and core ideas (design philosophies)
* Internal documentation, autodoc, Python and JS domains
* QWeb code documentation/description
* Documentation of the OpenERP APIs and choices taken based on that?
* Style guide and coding conventions (PEP8? More)
* Test frameworks in JS?
Standard Views
--------------
Search View
+++++++++++
The OpenERP search view really is a sub-view, used in support of views
acting on collections of records (list view or graph view, for
instance).
Its main goal is to collect information from its widgets (themselves
collecting information from the users) and make those available to the
rest of the client.
The search view's root is :js:class:`~openerp.base.SearchView`. This
object should never need to be created or managed directly, its
lifecycle should be driven by the
:js:class:`~openerp.base.ViewManager`.
.. TODO: insert SearchView constructor here
The search view defines a number of internal and external protocols to
communicate with the objects around and within it. Most of these
protocols are informal, and types available for inheritance are more
mixins than mandatory.
Events
""""""
``on_loaded``
.. TODO: method openerp.base.SearchView.on_loaded
Fires when the search view receives its view data (the result of
``fields_view_get``). Hooking up before the event allows for
altering view data before it can be used.
By the time ``on_loaded`` is done, the search view is guaranteed to
be fully set up and ready to use.
``on_search``
.. TODO: method openerp.base.SearchView.on_search
Event triggered after a user asked for a search. The search view
fires this event after collecting all input data (contexts, domains
and group_by contexts). Note that the search view does *not* merge
those (or otherwise evaluate them), they are returned as provided by
the various inputs within the view.
``on_clear``
.. TODO: method openerp.base.SearchView.on_clear
Triggered after a user asked for a form clearing.
Input management
""""""""""""""""
An important concept in the search view is that of input. It is both
an informal protocol and an abstract type that can be inherited from.
Inputs are widgets which can contain user data (a char widget for
instance, or a selection box). They are capable of action and of
reaction:
.. _views-search-registration:
``registration``
This is an input action. Inputs have to register themselves to the
main view (which they receive as a constructor argument). This is
performed by pushing themselves on the
:js:attr:`openerp.base.SearchView.inputs` array.
``get_context``
An input reaction. When it needs to collect contexts, the view calls
``get_context()`` on all its inputs.
Inputs can react in the following manners:
* Return a context (an object), this is the "normal" response if the
input holds a value.
* Return a value that evaluates as false (generally ``null``). This
value indicates the input does not contain any value and will not
affect the results of the search.
* Raise :js:class:`openerp.base.search.Invalid` to indicate that it
holds a value but this value can not be used in the search
(because it is incorrectly formatted or nonsensical). Raising
:js:class:`~openerp.base.search.Invalid` is guaranteed to cancel
the search process.
:js:class:`~openerp.base.search.Invalid` takes three mandatory
arguments: an identifier (a name for instance), the invalid value,
and a validation message indicating the issue.
``get_domain``
The second input reaction, the possible behaviors of inputs are the
same as for ``get_context``.
The :js:class:`openerp.base.search.Input` type implements registration
on its own, but its implementations of ``get_context`` and
``get_domain`` simply raise errors and *must* be overridden.
One last action is for filters, as an activation order has to be kept
on them for some controls (to establish the correct grouping sequence,
for instance).
To that end, filters can call
:js:func:`openerp.base.Search.do_toggle_filter`, providing themselves
as first argument.
Filters calling :js:func:`~openerp.base.Search.do_toggle_filter` also
need to implement a method called
:js:func:`~openerp.base.search.Filter.is_enabled`, which the search
view will use to know the current status of the filter.
The search view automatically triggers a search after calls to
:js:func:`~openerp.base.Search.do_toggle_filter`.
Life cycle
""""""""""
The search view has a pretty simple and linear life cycle, in three main steps:
:js:class:`~openerp.base.SearchView.init`
Nothing interesting happens here
:js:func:`~openerp.base.SearchView.start`
Called by the main view's creator, this is the main initialization
step for the list view.
It begins with a remote call to fetch the view's descriptors
(``fields_view_get``).
Once the remote call is complete, the ``on_loaded`` even happens,
holding three main operations:
:js:func:`~openerp.base.SearchView.make_widgets`
Builds and returns the top-level widgets of the search
view. Because it returns an array of widget lines (a 2-dimensional
matrix of widgets) it should be called recursively by container
widgets (:js:class:`openerp.base.search.Group` for instance).
:js:func:`~openerp.base.search.Widget.render`
Called by the search view on all top-level widgets. Container
widgets should recursively call this method on their own children
widgets.
Widgets are provided with a mapping of ``{name: value}`` holding
default values for the search view. They can freely pick their
initial values from there, but must pass the mapping to their
children widgets if they have any.
:js:func:`~openerp.base.search.Widget.start`
The last operation of the search view startup is to initialize all
its widgets in order. This is again done recursively (the search
view starts its children, which have to start their own children).
:js:func:`~openerp.base.SearchView.stop`
Used before discarding a search view, allows the search view to
disable its events and pass the message to its own widgets,
gracefully shutting down the whole view.
Widgets
"""""""
In a search view, the widget is simply a unit of display.
All widgets must be able to react to three events, which will be
called in this order:
:js:func:`~openerp.base.search.Widget.render`
Called with a map of default values. The widget must return a
``String``, which is its HTML representation. That string can be
empty (if the widget should not be represented).
Widgets are responsible for asking their children for rendering, and
for passing along the default values.
:js:func:`~openerp.base.search.Widget.start`
Called without arguments. At this point, the widget has been fully
rendered and can set its events up, if any.
The widget is responsible for starting its children, if it has any.
:js:func:`~openerp.base.search.Widget.stop`
Gives the widget the opportunity to unbind its events, remove itself
from the DOM and perform any other cleanup task it may have.
Even if the widget does not do anything itself, it is responsible
for shutting down its children.
An abstract type is available and can be inherited from, to simplify
the implementation of those tasks:
.. TODO: insert Widget here
.. remember to document all methods
Inputs
""""""
The search namespace (``openerp.base.search``) provides two more
abstract types, used to implement input widgets:
* :js:class:`openerp.base.search.Input` is the most basic input type,
it only implements :ref:`input registration
<views-search-registration>`.
If inherited from, descendant classes should not call its
implementations of :js:func:`~openerp.base.search.Input.get_context`
and :js:func:`~openerp.base.search.Input.get_domain`.
* :js:class:`openerp.base.search.Field` is used to implement more
"field" widgets (which allow the user to input potentially complex
values).
It provides various services for its subclasses:
* Sets up the field attributes, using attributes from the field and
the view node.
* It fills the widget with :js:class:`~openerp.base.search.Filter`
if the field has any child filter.
* It automatically generates an identifier based on the field type
and the field name, using
:js:func:`~openerp.base.search.Widget.make_id`.
* It sets up a basic (overridable)
:js:attr:`~openerp.base.search.Field.template` attribute, combined
with the previous tasks, this makes subclasses of
:js:class:`~openerp.base.search.Field` render themselves "for
free".
* It provides basic implementations of ``get_context`` and
``get_domain``, both hinging on the subclasses implementing
``get_value()`` (which should return a correct, converted
Javascript value):
:js:func:`~openerp.base.search.Field.get_context`
Checks if the field has a non-``null`` and non-empty
(``String``) value, and that the field has a ``context`` attr.
If both conditions are fullfilled, returns the context.
:js:func:`~openerp.base.search.Field.get_domain`
Only requires that the field has a non-``null`` and non-empty
value.
If the field has a ``filter_domain``, returns it
immediately. Otherwise, builds a context using the field's
name, the field :js:attr:`~openerp.base.search.Field.operator`
and the field value, and returns it.
.. TODO: insert Input, Field, Filter, and just about every Field subclass
List View
+++++++++
OpenERP Web's list views don't actually exist as such in OpenERP itself: a
list view is an OpenERP tree view in the ``view_mode`` form.
The overall purpose of a list view is to display collections of objects in two
main forms: per-object, where each object is a row in and of itself, and
grouped, where multiple objects are represented with a single row providing
an aggregated view of all grouped objects.
These two forms can be mixed within a single list view, if needed.
The root of a list view is :js:class:`openerp.base.ListView`, which may need
to be overridden (partially or fully) to control list behavior in non-view
cases (when using a list view as sub-component of a form widget for instance).
Creation and Initialization
"""""""""""""""""""""""""""
As with most OpenERP Web views, the list view's
:js:func:`~openerp.base.ListView.init` takes quite a number of arguments.
While most of them are the standard view constructor arguments
(``view_manager``, ``session``, ``element_id``, ``dataset`` and an
optional ``view_id``), the list view adds a number of options for basic
customization (without having to override methods or templates):
``selectable`` (default: ``true``)
Indicates that the list view should allow records to be selected
individually. Displays selection check boxes to the left of all record rows,
and allows for the triggering of the
:ref:`selection event <listview-events-selection>`.
``deletable`` (default: ``true``)
Indicates that the list view should allow records to be removed
individually. Displays a deletion button to the right of all record rows,
and allows for the triggering of the
:ref:`deletion event <listview-events-deletion>`.
``header`` (default: ``true``)
Indicates that list columns should bear a header sporting their name (for
non-action columns).
``addable`` (default: ``"New"``)
Indicates that a record addition/creation button should be displayed in
the list's header, along with its label. Also allows for the triggering of
the :ref:`record addition event <listview-events-addition>`.
``sortable`` (default: ``true``)
Indicates that the list view can be sorted per-column (by clicking on its
column headers).
.. TODO: event?
``reorderable`` (default: ``true``)
Indicates that the list view records can be reordered (and re-sequenced)
by drag and drop.
.. TODO: event?
Events
""""""
.. _listview-events-addition:
Addition
''''''''
The addition event is used to add a record to an existing list view. The
default behavior is to switch to the form view, on a new record.
Addition behavior can be overridden by replacing the
:js:func:`~openerp.base.ListView.do_add_record` method.
.. _listview-events-selection:
Selection
'''''''''
The selection event is triggered when a given record is selected in the list
view.
It can be overridden by replacing the
:js:func:`~openerp.base.ListView.do_select` method.
The default behavior is simply to hide or display the list-wise deletion button
depending on whether there are selected records or not.
.. _listview-events-deletion:
Deletion
''''''''
The deletion event is triggered when the user tries to remove 1..n records from
the list view, either individually or globally (via the header button).
Deletion can be overridden by replacing the
:js:func:`~openerp.base.ListView.do_delete` method. By default, this method
calls :js:func:`~openerp.base.DataSet.unlink` in order to remove the records
entirely.
.. note::
the list-wise deletion button (next to the record addition button)
simply proxies to :js:func:`~openerp.base.ListView.do_delete` after
obtaining all selected record ids, but it is possible to override it
alone by replacing
:js:func:`~openerp.base.ListView.do_delete_selected`.
Internal API Doc
----------------
Python
++++++
These classes should be moved to other sections of the doc as needed,
probably.
.. automodule:: web.common.http
:members:
:undoc-members:
See also: :class:`~web.common.session.OpenERPSession`,
:class:`~web.common.openerplib.main.OpenERPModel`
.. automodule:: web.controllers.main
:members:
:undoc-members:
Testing
-------
Python
++++++
Testing for the OpenERP Web core is similar to :ref:`testing addons
<addons-testing>`: the tests live in ``openerpweb.tests``, unittest2_
is the testing framework and tests can be run via either unittest2
(``unit2 discover``) or via nose_ (``nosetests``).
Tests for the OpenERP Web core can also be run using ``setup.py
test``.
.. _unittest2:
http://www.voidspace.org.uk/python/articles/unittest2.shtml
.. _nose:
http://somethingaboutorange.com/mrl/projects/nose/1.0.0/

View File

@ -1,10 +0,0 @@
Getting Started with OpenERP Web
================================
Installing
----------
.. per-distro packaging
Launching
---------

View File

@ -22,20 +22,6 @@ Contents:
list-view
form-notes
Older stuff
-----------
.. toctree::
:maxdepth: 2
getting-started
production
widgets
addons
development
project
old-version
Indices and tables
==================

View File

@ -1,11 +0,0 @@
Main differences with the 6.0 client
====================================
.. No more populate.sh, use virtualenvs
.. Logic is mainly in Javascript (had to make a choice between JS and
.. Python logic)
.. Templating language changes
.. How to port addons and modules?

View File

@ -1,47 +0,0 @@
Deploying OpenERP Web
=====================
.. After release one, add upgrade instructions if any
.. How about running the web client on alternative Python
.. implementations e.g. pypy or Jython? Since the only lib with C
.. accelerators we're using right now is SimpleJSON and it has a pure
.. Python base component, we should be able to test and deploy on
.. non-cpython no?
In-depth configuration
----------------------
SSL, basic proxy (link to relevant section), links to sections and
example files for various servers and proxies, WSGI
integration/explanation (if any), ...
Deployment Options
------------------
Serving via WSGI
~~~~~~~~~~~~~~~~
Apache mod_wsgi
+++++++++++++++
NGinx mod_wsgi
++++++++++++++
uWSGI
+++++
Gunicorn
++++++++
FastCGI, SCGI, or AJP
+++++++++++++++++++++
Behind a proxy
~~~~~~~~~~~~~~
Apache mod_proxy
++++++++++++++++
NGinx HttpProxy
+++++++++++++++

View File

@ -1,451 +0,0 @@
The OpenERP Web open-source project
===================================
Getting involved
----------------
Translations
++++++++++++
Bug reporting
+++++++++++++
Source code repository
++++++++++++++++++++++
Merge proposals
+++++++++++++++
Coding issues and coding conventions
++++++++++++++++++++++++++++++++++++
Javascript coding
~~~~~~~~~~~~~~~~~
These are a number of guidelines for javascript code. More than coding
conventions, these are warnings against potentially harmful or sub-par
constructs.
Ideally, you should be able to configure your editor or IDE to warn you against
these kinds of issues.
Use ``var`` for *all* declarations
**********************************
In javascript (as opposed to Python), assigning to a variable which does not
already exist and is not explicitly declared (via ``var``) will implicitly
create a global variable. This is bad for a number of reasons:
* It leaks information outside function scopes
* It keeps memory of previous run, with potentially buggy behaviors
* It may conflict with other functions with the same issue
* It makes code harder to statically check (via e.g. IDE inspectors)
.. note::
It is perfectly possible to use ``var`` in ``for`` loops:
.. code-block:: javascript
for (var i = 0; i < some_array.length; ++i) {
// code here
}
this is not an issue
All local *and global* variables should be declared via ``var``.
.. note:: generally speaking, you should not need globals in OpenERP Web: you
can just declare a variable local to your top-level function. This
way, if your widget/addon is instantiated several times on the same
page (because it's used in embedded mode) each instance will have its
own internal but global-to-its-objects data.
Do not leave trailing commas in object literals
***********************************************
While it is legal to leave trailing commas in Python dictionaries, e.g.
.. code-block:: python
foo = {
'a': 1,
'b': 2,
}
and it's valid in ECMAScript 5 and most browsers support it in Javascript, you
should *never* use trailing commas in Javascript object literals:
* Internet Explorer does *not* support trailing commas (at least until and
including Internet Explorer 8), and trailing comma will cause hard-to-debug
errors in it
* JSON does not accept trailing comma (it is a syntax error), and using them
in object literals puts you at risks of using them in literal JSON strings
as well (though there are few reasons to write JSON by hand)
*Never* use ``for … in`` to iterate on arrays
*********************************************
:ref:`Iterating over an object with for…in is a bit tricky already
<for-in-iteration>`, it is far more complex than in Python (where it Just
Works™) due to the interaction of various Javascript features, but to iterate
on arrays it becomes downright deadly and errorneous: ``for…in`` really
iterates over an *object*'s *properties*.
With an array, this has the following consequences:
* It does not necessarily iterate in numerical order, nor does it iterate in
any kind of set order. The order is implementation-dependent and may vary
from one run to the next depending on a number of reasons and implementation
details.
* If properties are added to an array, to ``Array.prototype`` or to
``Object.prototype`` (the latter two should not happen in well-behaved
javascript code, but you never know...) those properties *will* be iterated
over by ``for…in``. While ``Object.hasOwnProperty`` will guard against
iterating prototype properties, they will not guard against properties set
on the array instance itself (as memoizers for instance).
Note that this includes setting negative keys on arrays.
For this reason, ``for…in`` should **never** be used on array objects. Instead,
you should use either a normal ``for`` or (even better, unless you have
profiled the code and found a hotspot) one of Underscore's array iteration
methods (`_.each`_, `_.map`_, `_.filter`_, etc...).
Underscore is guaranteed to be bundled and available in OpenERP Web scopes.
.. _for-in-iteration:
Use ``hasOwnProperty`` when iterating on an object with ``for … in``
********************************************************************
``for…in`` is Javascript's built-in facility for iterating over and object's
properties.
`It is also fairly tricky to use`_: it iterates over *all* non-builtin
properties of your objects [#]_, which includes methods of an object's class.
As a result, when iterating over an object with ``for…in`` the first line of
the body *should* generally be a call to `Object.hasOwnProperty`_. This call
will check whether the property was set directly on the object or comes from
the object's class:
.. code-block:: javascript
for(var key in ob) {
if (!ob.hasOwnProperty(key)) {
// comes from ob's class
continue;
}
// do stuff with key
}
Since properties can be added directly to e.g. ``Object.prototype`` (even
though it's usually considered bad style), you should not assume you ever know
which properties ``for…in`` is going to iterate over.
An alternative is to use Underscore's iteration methods, which generally work
over objects as well as arrays:
Instead of
.. code-block:: javascript
for (var key in ob) {
if (!ob.hasOwnProperty(key)) { continue; }
var value = ob[key];
// Do stuff with key and value
}
you could write:
.. code-block:: javascript
_.each(ob, function (value, key) {
// do stuff with key and value
});
and not worry about the details of the iteration: underscore should do the
right thing for you on its own [#]_.
Writing documentation
+++++++++++++++++++++
The OpenERP Web project documentation uses Sphinx_ for the literate
documentation (this document for instance), the development guides
(for Python and Javascript alike) and the Python API documentation
(via autodoc_).
For the Javascript API, documentation should be written using the
`JsDoc Toolkit`_.
Guides and main documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The meat and most important part of all documentation. Should be
written in plain English, using reStructuredText_ and taking advantage
of `Sphinx's extensions`_, especially `cross-references`_.
Python API Documentation
~~~~~~~~~~~~~~~~~~~~~~~~
All public objects in Python code should have a docstring written in
RST, using Sphinx's `Python domain`_ [#]_:
* Functions and methods documentation should be in their own
docstring, using Sphinx's `info fields`_
For parameters types, built-in and stdlib types should be using the
combined syntax:
.. code-block:: restructuredtext
:param dict foo: what the purpose of foo is
unless a more extensive explanation needs to be given (e.g. the
specification that the input should be a list of 3-tuple needs to
use ``:type:`` even though all types involved are built-ins). Any
other type should be specified in full using the ``:type:`` field
.. code-block:: restructuredtext
:param foo: what the purpose of foo is
:type foo: some.addon.Class
Mentions of other methods (including within the same class), modules
or types in descriptions (of anything, including parameters) should
be cross-referenced.
* Classes should likewise be documented using their own docstring, and
should include the documentation of their construction (``__init__``
and ``__new__``), using the `info fields`_ as well.
* Attributes (class and instance) should be documented in their
class's docstring via the ``.. attribute::`` directive, following
the class's own documentation.
* The relation between modules and module-level attributes is similar:
modules should be documented in their own docstring, public module
attributes should be documented in the module's docstring using the
``.. data::`` directive.
Javascript API documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Javascript API documentation uses JsDoc_, a javascript documentation
toolkit with a syntax similar to (and inspired by) JavaDoc's.
Due to limitations of JsDoc, the coding patterns in OpenERP Web and
the Sphinx integration, there are a few peculiarities to be aware of
when writing javascript API documentation:
* Namespaces and classes *must* be explicitly marked up even if they
are not documented, or JsDoc will not understand what they are and
will not generate documentation for their content.
As a result, the bare minimum for a namespace is:
.. code-block:: javascript
/** @namespace */
foo.bar.baz = {};
while for a class it is:
.. code-block:: javascript
/** @class */
foo.bar.baz.Qux = [...]
* Because the OpenERP Web project uses `John Resig's Class
implementation`_ instead of direct prototypal inheritance [#]_,
JsDoc fails to infer class scopes (and constructors or super
classes, for that matter) and has to be told explicitly.
See :ref:`js-class-doc` for the complete rundown.
* Much like the JavaDoc, JsDoc does not include a full markup
language. Instead, comments are simply marked up in HTML.
This has a number of inconvenients:
* Complex documentation comments become nigh-unreadable to read in
text editors (as opposed to IDEs, which may handle rendering
documentation comments on the fly)
* Though cross-references are supported by JsDoc (via ``@link`` and
``@see``), they only work within the JsDoc
* More general impossibility to integrate correctly with Sphinx, and
e.g. reference JavaScript objects from a tutorial, or have all the
documentation live at the same place.
As a result, JsDoc comments should be marked up using RST, not
HTML. They may use Sphinx's cross-references as well.
.. _js-class-doc:
Documenting a Class
*******************
The first task when documenting a class using JsDoc is to *mark* that
class, so JsDoc knows it can be used to instantiate objects (and, more
importantly as far as it's concerned, should be documented with
methods and attributes and stuff).
This is generally done through the ``@class`` tag, but this tag has a
significant limitation: it "believes" the constructor and the class
are one and the same [#]_. This will work for constructor-less
classes, but because OpenERP Web uses Resig's class the constructor is
not the class itself but its ``init()`` method.
Because this pattern is common in modern javascript code bases, JsDoc
supports it: it is possible to mark an arbitrary instance method as
the *class specification* by using the ``@constructs`` tag.
.. warning:: ``@constructs`` is a class specification in and of
itself, it *completely replaces* the class documentation.
Using both a class documentation (even without ``@class`` itself)
and a constructor documentation is an *error* in JsDoc and will
result in incorrect behavior and broken documentation.
The second issue is that Resig's class uses an object literal to
specify instance methods, and because JsDoc does not know anything
about Resig's class, it does not know about the role of the object
literal.
As with constructors, though, JsDoc provides a pluggable way to tell
it about methods: the ``@lends`` tag. It specifies that the object
literal "lends" its properties to the class being built.
``@lends`` must be specified right before the opening brace of the
object literal (between the opening paren of the ``#extend`` call and
the brace), and takes the full qualified name of the class being
created as a parameter, followed by the character ``#`` or by
``.prototype``. This latter part tells JsDoc these are instance
methods, not class (static) methods..
Finally, specifying a class's superclass is done through the
``@extends`` tag, which takes a fully qualified class name as a
parameter.
Here are a class without a constructor, and a class with one, so that
everything is clear (these are straight from the OpenERP Web source,
with the descriptions and irrelevant atttributes stripped):
.. code-block:: javascript
/**
* <Insert description here, not below>
*
* @class
* @extends openerp.base.search.Field
*/
openerp.base.search.CharField = openerp.base.search.Field.extend(
/** @lends openerp.base.search.CharField# */ {
// methods here
});
.. code-block:: javascript
openerp.base.search.Widget = openerp.base.Controller.extend(
/** @lends openerp.base.search.Widget# */{
/**
* <Insert description here, not below>
*
* @constructs
* @extends openerp.base.Controller
*
* @param view the ancestor view of this widget
*/
init: function (view) {
// construction of the instance
},
// bunch of other methods
});
OpenERP Web over time
---------------------
Release process
+++++++++++++++
OpenSUSE packaging: http://blog.lowkster.com/2011/04/packaging-python-packages-in-opensuse.html
Roadmap
+++++++
Release notes
+++++++++++++
.. [#] More precisely, it iterates over all *enumerable* properties. It just
happens that built-in properties (such as ``String.indexOf`` or
``Object.toString``) are set to non-enumerable.
The enumerability of a property can be checked using
`Object.propertyIsEnumeable`_.
Before ECMAScript 5, it was not possible for user-defined properties
to be non-enumerable in a portable manner. ECMAScript 5 introduced
`Object.defineProperty`_ which lets user code create non-enumerable
properties (and more, read-only properties for instance, or implicit
getters and setters). However, support for these is not fully complete
at this point, and they are not being used in OpenERP Web code anyway.
.. [#] While using underscore is generally the preferred method (simpler,
more reliable and easier to write than a *correct* ``for…in``
iteration), it is also probably slower (due to the overhead of
calling a bunch of functions).
As a result, if you profile some code and find out that an underscore
method adds unacceptable overhead in a tight loop, you may want to
replace it with a ``for…in`` (or a regular ``for`` statement for
arrays).
.. [#] Because Python is the default domain, the ``py:`` markup prefix
is optional and should be left out.
.. [#] Resig's Class still uses prototypes under the hood, it doesn't
reimplement its own object system although it does add several
helpers such as the ``_super()`` instance method.
.. [#] Which is the case in normal Javascript semantics. Likewise, the
``.prototype`` / ``#`` pattern we will see later on is due to
JsDoc defaulting to the only behavior it can rely on: "normal"
Javascript prototype-based type creation.
.. _reStructuredText:
http://docutils.sourceforge.net/rst.html
.. _Sphinx:
http://sphinx.pocoo.org/index.html
.. _Sphinx's extensions:
http://sphinx.pocoo.org/markup/index.html
.. _Python domain:
http://sphinx.pocoo.org/domains.html#the-python-domain
.. _info fields:
http://sphinx.pocoo.org/domains.html#info-field-lists
.. _autodoc:
http://sphinx.pocoo.org/ext/autodoc.html
?highlight=autodoc#sphinx.ext.autodoc
.. _cross-references:
http://sphinx.pocoo.org/markup/inline.html#xref-syntax
.. _JsDoc:
.. _JsDoc Toolkit:
http://code.google.com/p/jsdoc-toolkit/
.. _John Resig's Class implementation:
http://ejohn.org/blog/simple-javascript-inheritance/
.. _\_.each:
http://documentcloud.github.com/underscore/#each
.. _\_.map:
http://documentcloud.github.com/underscore/#map
.. _\_.filter:
http://documentcloud.github.com/underscore/#select
.. _It is also fairly tricky to use:
https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in#Description
.. _Object.propertyIsEnumeable:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable
.. _Object.defineProperty:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
.. _Object.hasOwnProperty:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

View File

@ -1,12 +0,0 @@
OpenERP Web as a widgets provider
=================================
* Using a readonly view as a widget
* Site example
* iGoogle example
* social site example e.g. Facebook app?
* Write-access widgets (e.g. contact form)
* Multiple widgets on the same page
* JSON-RPC2 API description for third-parties?