Author: |
Trobz |
License: |
no license |
Branch: |
7.0-web-unleashed-195542 |
Repository: |
trobz/web |
Dependencies: |
web |
Languages: |
CSS (10, 0.2%),
JavaScript (5154, 91.9%),
Markdown (334, 6.0%),
Python (78, 1.4%),
and
XML (33, 0.6%) |
Other repositories: |
IlyasRakhimkulov/openerp-web-unleashed,
Nucleoos/openerp-web-unleashed,
OdooBulgaria/openerp-web-unleashed,
OpenStone/openerp-web-unleashed,
Shebak/openerp-web-unleashed,
VbossEkat/openerp-web-unleashed,
alhashash/openerp-web-unleashed,
anhvu-sg/openerp-web-unleashed,
ashnur/openerp-web-unleashed,
dw250100785/openerp-web-unleashed,
gitlabuser/openerp-web-unleashed,
gsunjka/openerp-web-unleashed,
jeffery9/openerp-web-unleashed,
judaa11/openerp-web-unleashed,
lmcclanahan/openerp-web-unleashed,
trobz/openerp-web-unleashed,
williamcastrillon/openerp-web-unleashed,
yelizariev/openerp-web-unleashed,
and
zuloloxi/openerp-web-unleashed |
<p><a href="https://travis-ci.org/trobz/openerp-web-unleashed"><img src="https://travis-ci.org/trobz/openerp-web-unleashed.png?branch=master" alt="Build Status"></a></p>
<p>By default, the web part of OpenERP is not easy, the documentation is minimalist and the architecture is hard to understand.</p>
<p>This is a pure web module with one objective: providing good bases to build rich web application in OpenERP.</p>
<h2>Features</h2>
<ul>
<li>clear MVC pattern, based on Backbone and Marionnette... with all their documentations ! </li>
<li>new namespace to organize and get access to your objects</li>
<li>full-featured Backbone Models with OpenERP JSON-RPC API support</li>
<li>QWeb rendering for Marionette views</li>
<li>base objects to build custom views (Pager, Grouped Collection, Extended OpenERP View, State manager...)</li>
<li>unit tests for basic functionalities</li>
<li>load/configuration commonly used libraries (momentjs, numeraljs, awesome-font,...) </li>
</ul>
<h2>Exemple</h2>
<p>Checkout the <a href="https://github.com/trobz/openerp-web-unleashed/tree/master/demo_todo">demo_todo module</a>, it's a full featured example with comments. </p>
<h3>Features</h3>
<ul>
<li>module initialization</li>
<li>Backbone data access with JSON-RPC API</li>
<li>layout definition based on Marionette</li>
<li>native OpenERP search widget support</li>
<li>pagination support</li>
<li>custom 'todo' view type</li>
</ul>
<h1>Architecture</h1>
<h2>Files organization</h2>
<p>A good architecture start with a good file organization. A common practice is to
separate each object in one fileand organize objects in logical folder.</p>
<p>A module build with Web Unleashed will look like:</p>
<p><code>
- static
- lib/ // all external lib dependencies
- src/
- js/
- models/
- collections/
- views/
- utils/ // any useful lib
- my_module.js // the web module entry point
- templates/ // QWeb templates
- tests/ // jsunit tests
- images/
- css/
- ...
</code></p>
<p>Note:
- this is a basic organization, <code>js</code> subfolder can have specific folders
to organize your module code logically.</p>
<h2>Unleashed namespace</h2>
<p><code>openerp.unleashed</code></p>
<p>This namespace is a Marionette Application, each web OpenERP module that uses
Unleashed are submodules of this Application.</p>
<p>A module object has few helpers to set/get object in his namespace:</p>
<p><code>js
// basic getter/setter
openerp.unleashed.module('my_module').set(namespace, name, object)
openerp.unleashed.module('my_module').get(namespace, name)
// helpers
openerp.unleashed.module('my_module').views(view_name, object)
openerp.unleashed.module('my_module').collections(collection_name, object)
openerp.unleashed.module('my_module').models(model_name, object)
openerp.unleashed.module('my_module').utils(name, object)
</code></p>
<p>Notes: </p>
<ul>
<li>you never have to call the full namespace path, the module object is always
passed to your module scope when you have declare a new object,
see <a href="#object-declaration">object declaration</a> for details </li>
<li>the module name has to be the technical name of your OpenERP module</li>
</ul>
<h3>Module initialization</h3>
<p>In OpenERP web, you need to define a method on openerp namespace to know
when OpenERP is ready to process your code, like this:</p>
<p><code>js
openerp.my_module = function(instance){
//openerp is ready to do stuff for your module !
};
</code></p>
<p>With Unleashed, you can declare a ready method as many time as you want,
and from anywhere, Unleashed will ensure that OpenERP is ready to execute your code.</p>
<p>In addition to ensure that OpenERP is fully loaded, some useful arguments
are passed to the function, like the base module object, the latest Backbone and Underscore version,
and the current module object.</p>
<p><code>js
openerp.unleashed.module('my_module').ready(function(instance, my_module, _, Backbone, base_module) {
// openerp is ready and you can benefit from
// the lastest Backbone and Underscore version here !
});
</code></p>
<p>Notes:</p>
<ul>
<li>Backbone and Underscore are already included in OpenERP, but they are using old version. Unleashed
include the latest version of these libraries in noConflict mode.</li>
</ul>
<h3>Object declaration</h3>
<p>To be able to split object in different files, and keep the code organization in the global scope,
you have to use the module scope.</p>
<p>In this scope, you have access to the module object, the base module object,
the latest Underscore and Backbone version.</p>
<p><strong>create a new object</strong></p>
<p>```js
openerp.unleashed.module('my<em>module', function(my</em>module, _, Backbone, base){
var _super = Backbone.View.prototype;
var GreatView = Backbone.View.extend({</p>
<pre><code> initialize: function(){
}
});
my_module.views('GreatView', GreatView);
</code></pre>
<p>});
```</p>
<p>In this example, a new view extend the basic Backbone View and is added
to <code>my_module</code> namespace with the name "GreatView".</p>
<p>Now you have access to this object from anywhere by simply using the name you used to declare it:</p>
<p><code>js
...
var GreatView = my_module.views('GreatView'),
view = new GreatView();
...
</code></p>
<p>Note:
- because OpenERP is not using an AMD/module loader system like RequireJS, you have
to ensure that your files are loaded in the correct order in <code>__openerp__.py</code> file.<br>
We are working on requirejs support for OpenERP, it's planned for the next release of unleashed.</p>
<h2>Base module</h2>
<p>Unleash provide some useful Backbone extension:</p>
<h3>JSON-RPC API Model support</h3>
<p>By using the <code>BaseModel</code> and <code>BaseCollection</code> from the base module,
the JSON-RPC API is automatically implemented.</p>
<p><strong>create a new "JSON-RPC API ready" collection</strong></p>
<p>```js
openerp.unleashed.module('my<em>module', function(my</em>module, _, Backbone, base){</p>
<pre><code>var BaseCollection = base.collections('BaseCollection'),
_super = BaseCollection.prototype;
var Employees = BaseCollection.extend({
model_name: 'hr.employee',
// your classic backbone code here !
});
my_module.collections('Employees', Employees);
</code></pre>
<p>});
```</p>
<p>Now, you are ready to use this model, somewhere else, you can do:</p>
<p>```js
openerp.unleashed.module('my<em>module', function(my</em>module, _, Backbone, base){</p>
<pre><code>var Employees = my_module.collections('Employees'),
employees = new Employees();
employees.fetch({
filter: [['name', 'like', 'toto']]
});
employees.done(function(){
//employees.length = nb employee in db with like '%toto%'
});
</code></pre>
<p>});
```</p>
<ul>
<li><code>employees</code> is a Backbone Collection, populated with Backbone Model, with all what it imply !</li>
<li>you can pass to <code>fetch</code> method all JSON-RPC API js client options:<br>
<code>filter</code>, <code>order</code>, <code>limit</code>, <code>offset</code>, <code>context</code>, <code>fields</code></li>
</ul>
<h3>Collection with <code>group_by</code> lazy loading support</h3>
<p>When you fetch your collection with a <code>group_by</code> option, the collection is populated
with special <code>GroupQuery</code> models.</p>
<p>These special Models are able to get the result of each groups, allowing to list the group first
in the interface and lazy load each of them after an action.</p>
<p>To get the result of each of them, you simply have to call <code>fetch</code> on them, the <code>GroupQuery</code>
will make an instance of the Collection his coming from and populate it with the groupment result.</p>
<p>Notes:
- if a grouped collection is fetched without a <code>group_by</code> query later,
the collection will be populated with "normal" model again.
- the Pager collection support <code>group_by</code> queries too, the pagination
is simply disabled during grouping queries.</p>
<p><strong>example</strong></p>
<p>```js
var BaseCollection = base.collections('BaseCollection'),
BaseModel = base.models('BaseModel'),
GroupQuery = base.models('GroupQuery');</p>
<p>var CustomGroupQuery = GroupQuery.extend({
some_method: function(){...}
});</p>
<p>var CustomModel = BaseModel.extend({
model_name: 'your.model'
});</p>
<p>var CustomCollection = BaseCollection.extend({
model_name: 'your.model',
model: CustomModel,</p>
<pre><code>/* you can define the GroupQuery to use when a collection is
* fetched with a group_by query, useful to add specific methods
* on group themself,
*/ otherwise GroupQuery Model is used instead
group_model: CustomGroupQuery
</code></pre>
<p>});</p>
<p>// create a new instance of collection
var collection = new CustomCollection();</p>
<p>var promise = collection.fetch({
group_by: ['type']
});</p>
<p>promise.done(function(){
/*
* the collection is populated with GroupQuery model
*/</p>
<pre><code>// collection.length == your.model grouped by type
// collection.grouped() == true
var group_query = collection.at(0);
// group_query instanceof CustomGroupQuery
// group_query.get('value') == type group name
// group_query.get('length') == number of element in the group
// collection where will be set group results
var list = group_query.group;
// list instanceof CustomCollection
// get all grouped items
var group_promise = group_query.fetch():
group_promise.done(function(){
/*
* the group is populated with Model
*/
// list.length == group_query.get('length')
var model = list.at(0);
// model instanceof CustomModel
});
</code></pre>
<p>});
```</p>
<h3>Unleashed View</h3>
<p>OpenERP View has been extended to add some default behavior/features.</p>
<p><strong>instanciation</strong></p>
<p>```js
openerp.unleashed.module('my<em>module').ready(function(instance, my</em>module, _, Backbone, base) {</p>
<pre><code>var UnleashedView = base.views('Unleashed');
instance.web.views.add('foo', 'instance.my_module.FooView');
instance.booking_chart.FooView = UnleashedView.extend({
display_name: base._lt('Foo'),
template: "Foo",
view_type: 'foo',
/*
* You can redefine views and models used by UnleashedView,
* specially for the State, usually each view has his own way
* to keep the view state persistent.
*
* Check comment on State and Panel objects for more details.
*/
Panel: base.views('Panel'),
State: base.models('State'),
/*
* Configure the state before processing it
* the state is processed after "start" and before "ready" execution.
*
* Depending of your state model, you will certainly have to configure it
* before his processing, usually by linking some objects and listening
* events to update the state.
*
* An example is available in "demo_todo" module.
*/
stateConfig: function(){
},
/*
* Executed by OpenERP before view loading, usual place to instanciate
* your views and models.
*/
start: function(){
},
/*
* Pre configure the view before state processing
*
* @param {Object} data
* View configuration object:
* - arch: Object
* - field_parent: Boolean
* - fields: Object
* - model: String
* - name: String
* - toolbar: Object
* - type: String
* - view_id: Integer
*/
configure: function(data){
},
/*
* The view is ready to be used, called by a listener on
* OpenERP View "view_loaded" event
*
* @param {Object} data
* View configuration object:
* - arch: Object
* - field_parent: Boolean
* - fields: Object
* - model: String
* - name: String
* - toolbar: Object
* - type: String
* - view_id: Integer
*/
ready: function(data){
/*
* A Marionette Panel is available,
* with all OpenERP part defined as Region:
* - this.panel.buttons
* - this.panel.pager
* - this.panel.sidebar
* - this.panel.body
*/
}
});
</code></pre>
<p>});
```</p>
<p>Features automatically handled by the Unleashed View:</p>
<ul>
<li>the State of the view is managed by a Model, automatically pushed into the URL at state
modification, you can extend the state model to had your own state logic.</li>
<li>add a Marionette Panel to manage all elements available in an OpenERP view:<br>
<code>buttons</code>, <code>sidebar</code>, <code>pager</code>, <code>body</code> regions. </li>
</ul>
<p>Checkout the <a href="https://github.com/trobz/openerp-web-unleashed/tree/master/demo_todo">demo_todo module</a> for more details.</p>
<p><strong>custom view type</strong></p>
<p>To support custom <code>view_type</code> in <code>ir.ui.view</code> model and to have specific view
description (use <code>arch</code> config,...), you have to extend the python <code>irUiView</code> model
and specify your new view.</p>
<p>You can add <code>arch</code> validation and build highly configurable view in the same way
than standard OpenERP views.</p>
<p>A simple example of a custom type declaration is available here:<br>
https://github.com/trobz/openerp-web-unleashed/blob/master/demo_todo/view/todo.py</p>
<h3>Pager</h3>
<p>Provide everything to have a pagination on your collection, similar than the OpenERP
one but without dependencies.</p>
<ul>
<li>Paginated collection</li>
<li>A pager view, with the same layout than the native OpenERP pager</li>
</ul>
<p>Checkout the <a href="https://github.com/trobz/openerp-web-unleashed/tree/master/demo_todo">demo_todo module</a> for more details.</p>
<h3>Iterator</h3>
<p>A Backbone collection with selectable model, this collection implement several methods like:<br>
<code>next</code>, <code>previous</code>, <code>first</code>, <code>last</code>, <code>select</code>,... </p>
<h2>Extra module</h2>
<p><code>web_unleashed_extra</code> module contain all libraries and widget not necessary
useful for all modules that uses unleashed.</p>
<ul>
<li>momentjs / numeraljs libraries</li>
<li>fontawesome library</li>
<li>twitter bootstrap, scoped with 'bootstrap-scoped' css class</li>
<li>extra base model
<ul>
<li>period model: used to manage a period of time as a Backbone Model</li>
</ul></li>
</ul>
<h1>Libraries</h1>
<ul>
<li><a href="http://backbonejs.org">Backbone 1.1.0</a></li>
<li><a href="http://underscorejs.org">Underscore 1.5.2</a></li>
<li><a href="https://github.com/marionettejs/backbone.marionette/">Marionnette 1.1.0</a></li>
</ul>
<p><strong>Libraries in extra module</strong></p>
<ul>
<li><a href="http://momentjs.com">MomentJS 2.0.0</a></li>
<li><a href="https://github.com/icambron/twix.js">MomentJS Twix Plugin 0.3</a></li>
<li><a href="http://adamwdraper.github.com/Numeral-js/">NumeralJS 1.4.9</a></li>
<li><a href="http://fontawesome.io">Font Awesome 3.2.1</a></li>
<li><a href="http://getbootstrap.com">Bootstrap 3.0.0</a><br>
note: all css selector are scoped with the class <code>.bootstrap_scope</code> to avoid css conflict.</li>
</ul>