1Guidelines and Recommendations 2============================== 3 4Web Module Recommendations 5-------------------------- 6 7Identifiers (``id`` attribute) should be avoided 8'''''''''''''''''''''''''''''''''''''''''''''''' 9 10In generic applications and modules, ``@id`` limits the reusabily of 11components and tends to make code more brittle. 12 13Just about all the time, they can be replaced with nothing, with 14classes or with keeping a reference to a DOM node or a jQuery element 15around. 16 17.. note:: 18 19 If it is *absolutely necessary* to have an ``@id`` (because a 20 third-party library requires one and can't take a DOM element), it 21 should be generated with `_.uniqueId 22 <http://underscorejs.org/#uniqueId>`_ or some other similar 23 method. 24 25Avoid predictable/common CSS class names 26'''''''''''''''''''''''''''''''''''''''' 27 28Class names such as "content" or "navigation" might match the desired 29meaning/semantics, but it is likely an other developer will have the 30same need, creating a naming conflict and unintended behavior. Generic 31class names should be prefixed with e.g. the name of the component 32they belong to (creating "informal" namespaces, much as in C or 33Objective-C) 34 35Global selectors should be avoided 36'''''''''''''''''''''''''''''''''' 37 38Because a component may be used several times in a single page (an 39example in OpenERP is dashboards), queries should be restricted to a 40given component's scope. Unfiltered selections such as ``$(selector)`` 41or ``document.querySelectorAll(selector)`` will generally lead to 42unintended or incorrect behavior. 43 44OpenERP Web's :js:class:`~openerp.web.Widget` has an attribute 45providing its DOM root :js:attr:`Widget.$el <openerp.web.Widget.$el>`, 46and a shortcut to select nodes directly :js:attr:`Widget.$ 47<openerp.web.Widget.$>`. 48 49More generally, never assume your components own or controls anything 50beyond its own personal DOM. 51 52Understand deferreds 53'''''''''''''''''''' 54 55Deferreds, promises, futures, … 56 57Known under many names, these objects are essential to and (in OpenERP 58Web) widely used for making :doc:`asynchronous javascript operations 59<async>` palatable and understandable. 60 61OpenERP Web guidelines 62---------------------- 63 64* HTML templating/rendering should use :doc:`qweb` unless absolutely 65 trivial. 66 67* All interactive components (components displaying information to the 68 screen or intercepting DOM events) must inherit from 69 :class:`~openerp.web.Widget` and correctly implement and use its API 70 and lifecycle. 71 72* All css classes must be prefixed with *oe_* . 73 74* Asynchronous functions (functions which call :ref:`session.rpc 75 <rpc_rpc>` directly or indirectly at the very least) *must* return 76 deferreds, so that callers of overriders can correctly synchronize 77 with them. 78 79New Javascript guidelines 80------------------------- 81 82From v11, we introduce a new coding standard for Odoo Javascript code. Here it 83is: 84 85* add "use strict"; on top of every odoo JS module 86 87* name all entities exported by a JS module. So, instead of 88 89 .. code-block:: javascript 90 91 return Widget.extend({ 92 ... 93 }); 94 95you should use: 96 97 .. code-block:: javascript 98 99 var MyWidget = Widget.extend({ 100 ... 101 }); 102 103 return MyWidget 104 105* there should be one space between function and the left parenthesis: 106 107 .. code-block:: javascript 108 109 function (a, b) {} 110 111* JS files should have a (soft) limit of 80 chars width, and a hard limit of 100 112 113* document every functions and every files, with the style JSDoc. 114 115* for function overriding other functions, consider adding the tag @override in 116 the JS Doc. Also, you can mention which method is overridden: 117 118 .. code-block:: javascript 119 120 /** 121 * When a save operation has been confirmed from the model, this method is 122 * called. 123 * 124 * @override method from field manager mixin 125 * @param {string} id 126 * @returns {Deferred} 127 */ 128 _confirmSave: function (id) { 129 130* there should be an empty line between the main function comments and the tags, 131 or parameter descriptions 132 133* avoid introspection: don't build dynamically a method name and call it. It is 134 more fragile and more difficult to refactor 135 136* methods should be private if possible 137 138* never read an attribute of an attribute on somethig that you have a reference. 139 So, this is not good: 140 141 .. code-block:: javascript 142 143 this.myObject.propA.propB 144 145* never use a reference to the parent widget 146 147* avoid using the 'include' functionality: extending a class is fine and does 148 not cause issue, including a class is much more fragile, and may not work. 149 150* For the widgets, here is how the various attributes/functions should be 151 ordered: 152 153 1. all static attributes, such as template, events, custom_events, ... 154 155 2. all methods from the lifecycle of a widget, in this order: init, willStart, 156 start, destroy 157 158 3. If there are public methods, a section titled "Public", with an empty line 159 before and after 160 161 4. all public methods, camelcased, in alphabetic order 162 163 5. If there are private methods, a section titled "Private", with an empty line 164 before and after 165 166 6. all private methods, camelcased and prefixed with _, in alphabetic order 167 168 7. If there are event handlers, a section titled "Handlers", with an empty line 169 before and after 170 171 8. all handlers, camelcased and prefixed with _on, in alphabetic order 172 173 9. If there are static methods, they should be in a section titled "Static". 174 All static methods are considered public, camelcased with no _. 175 176* write unit tests 177 178* for the event handlers defined by the key 'event' or 'custom_events', don't 179 inline the function. Always add a string name, and add the definition in the 180 handler section 181 182* one space after if and for 183 184* never call private methods on another object 185 186* object definition on more than one line: each element should have a trailing 187 comma. 188 189* strings: double quotes for all textual strings (such as "Hello"), and single 190 quotes for all other strings, such as a css selector '.o_form_view' 191 192* always use this._super.apply(this, arguments); 193 194* keys in an object: ordered by alphabetic order