Merge lp:~openerp-dev/openerp-web/7.0-module-tutorial-xmo into lp:openerp-web/7.0

Proposed by Xavier (Open ERP)
Status: Rejected
Rejected by: Xavier (Open ERP)
Proposed branch: lp:~openerp-dev/openerp-web/7.0-module-tutorial-xmo
Merge into: lp:openerp-web/7.0
Diff against target: 1537 lines (+882/-283)
49 files modified
addons/web/doc/conf.py (+5/-1)
addons/web/doc/module.rst (+195/-36)
addons/web/doc/module/0 (+17/-0)
addons/web/doc/module/10 (+13/-0)
addons/web/doc/module/11 (+11/-0)
addons/web/doc/module/12 (+28/-0)
addons/web/doc/module/14 (+17/-0)
addons/web/doc/module/15 (+19/-0)
addons/web/doc/module/16 (+25/-0)
addons/web/doc/module/17 (+52/-0)
addons/web/doc/module/18 (+19/-0)
addons/web/doc/module/19 (+52/-0)
addons/web/doc/module/2 (+12/-0)
addons/web/doc/module/20 (+64/-0)
addons/web/doc/module/21 (+27/-0)
addons/web/doc/module/22 (+6/-0)
addons/web/doc/module/23 (+14/-0)
addons/web/doc/module/24 (+10/-0)
addons/web/doc/module/25 (+55/-0)
addons/web/doc/module/26 (+38/-0)
addons/web/doc/module/27 (+28/-0)
addons/web/doc/module/28 (+13/-0)
addons/web/doc/module/29 (+37/-0)
addons/web/doc/module/3 (+9/-0)
addons/web/doc/module/4 (+11/-0)
addons/web/doc/module/5 (+11/-0)
addons/web/doc/module/6 (+29/-0)
addons/web/doc/module/8 (+14/-0)
addons/web/doc/module/9 (+21/-0)
addons/web/doc/module/__openerp__.py (+0/-7)
addons/web/doc/module/__openerp__.py.1.diff (+0/-11)
addons/web/doc/module/__openerp__.py.2.diff (+0/-11)
addons/web/doc/module/__openerp__.py.3.diff (+0/-12)
addons/web/doc/module/__openerp__.py.4.diff (+0/-13)
addons/web/doc/module/__openerp__.py.5.diff (+0/-14)
addons/web/doc/module/series (+27/-0)
addons/web/doc/module/static/src/css/web_example.css (+0/-6)
addons/web/doc/module/static/src/css/web_example.css.1.diff (+0/-17)
addons/web/doc/module/static/src/js/first_module.js (+0/-2)
addons/web/doc/module/static/src/js/first_module.js.1.diff (+0/-8)
addons/web/doc/module/static/src/js/first_module.js.2.diff (+0/-11)
addons/web/doc/module/static/src/js/first_module.js.3.diff (+0/-18)
addons/web/doc/module/static/src/js/first_module.js.4.diff (+0/-15)
addons/web/doc/module/static/src/js/first_module.js.5.diff (+0/-23)
addons/web/doc/module/static/src/js/first_module.js.6.diff (+0/-55)
addons/web/doc/module/static/src/xml/web_example.xml (+0/-11)
addons/web/doc/module/web_example.xml (+0/-11)
addons/web/doc/testing.rst (+2/-0)
addons/web/doc/widget.rst (+1/-1)
To merge this branch: bzr merge lp:~openerp-dev/openerp-web/7.0-module-tutorial-xmo
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+148709@code.launchpad.net
To post a comment you must log in.
3739. By Xavier (Open ERP)

[WIP] testing in module guide

3740. By Xavier (Open ERP)

[IMP] final section of the module guide

Revision history for this message
Xavier (Open ERP) (xmo-deactivatedaccount) wrote :

was merged into trunk, so cancelling this proposal

Unmerged revisions

3740. By Xavier (Open ERP)

[IMP] final section of the module guide

3739. By Xavier (Open ERP)

[WIP] testing in module guide

3738. By Xavier (Open ERP)

[ADD] sync-on-start tutoring

3737. By Xavier (Open ERP)

[IMP] replace ad-hoc patch display by patchqueue

3736. By Xavier (Open ERP)

[IMP] web module tutorial: start adding RPC stuff

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'addons/web/doc/conf.py'
--- addons/web/doc/conf.py 2013-01-17 09:27:22 +0000
+++ addons/web/doc/conf.py 2013-02-18 15:08:21 +0000
@@ -27,7 +27,11 @@
2727
28# Add any Sphinx extension module names here, as strings. They can be extensions28# Add any Sphinx extension module names here, as strings. They can be extensions
29# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.29# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
30extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.viewcode']30extensions = [
31 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
32 'sphinx.ext.todo', 'sphinx.ext.viewcode',
33 'patchqueue'
34]
3135
32# Add any paths that contain templates here, relative to this directory.36# Add any paths that contain templates here, relative to this directory.
33templates_path = ['_templates']37templates_path = ['_templates']
3438
=== modified file 'addons/web/doc/module.rst'
--- addons/web/doc/module.rst 2013-01-17 09:27:22 +0000
+++ addons/web/doc/module.rst 2013-02-18 15:08:21 +0000
@@ -1,5 +1,7 @@
1.. _module:1.. _module:
22
3.. queue:: module/series
4
3Building an OpenERP Web module5Building an OpenERP Web module
4==============================6==============================
57
@@ -19,8 +21,7 @@
19 ├── __init__.py21 ├── __init__.py
20 └── __openerp__.py22 └── __openerp__.py
2123
22.. literalinclude:: module/__openerp__.py24.. patch::
23 :language: python
2425
25This is a sufficient minimal declaration of a valid OpenERP module.26This is a sufficient minimal declaration of a valid OpenERP module.
2627
@@ -41,8 +42,7 @@
41is the extent of it. You should also change the dependency to list42is the extent of it. You should also change the dependency to list
42``web``:43``web``:
4344
44.. literalinclude:: module/__openerp__.py.1.diff45.. patch::
45 :language: diff
4646
47.. note::47.. note::
4848
@@ -67,15 +67,13 @@
67``static/src/js``, to have room for e.g. other file types, or67``static/src/js``, to have room for e.g. other file types, or
68third-party libraries.68third-party libraries.
6969
70.. literalinclude:: module/static/src/js/first_module.js70.. patch::
71 :language: javascript
7271
73The client won't load any file unless specified, thus the new file72The client won't load any file unless specified, thus the new file
74should be listed in the module's manifest file, under a new key ``js``73should be listed in the module's manifest file, under a new key ``js``
75(a list of file names, or glob patterns):74(a list of file names, or glob patterns):
7675
77.. literalinclude:: module/__openerp__.py.2.diff76.. patch::
78 :language: diff
7977
80At this point, if the module is installed and the client reloaded the78At this point, if the module is installed and the client reloaded the
81message should appear in your browser's development console.79message should appear in your browser's development console.
@@ -100,8 +98,7 @@
100client (such as making RPC requests to the server). This is done by98client (such as making RPC requests to the server). This is done by
101providing a `javascript module`_:99providing a `javascript module`_:
102100
103.. literalinclude:: module/static/src/js/first_module.js.1.diff101.. patch::
104 :language: diff
105102
106If you reload the client, you'll see a message in the console exactly103If you reload the client, you'll see a message in the console exactly
107as previously. The differences, though invisible at this point, are:104as previously. The differences, though invisible at this point, are:
@@ -122,17 +119,12 @@
122119
123First, the action declaration:120First, the action declaration:
124121
125.. literalinclude:: module/__openerp__.py.3.diff122.. patch::
126 :language: diff
127
128.. literalinclude:: module/web_example.xml
129 :language: xml
130123
131then set up the :doc:`client action hook <client_action>` to register124then set up the :doc:`client action hook <client_action>` to register
132a function (for now):125a function (for now):
133126
134.. literalinclude:: module/static/src/js/first_module.js.2.diff127.. patch::
135 :language: diff
136128
137Updating the module (in order to load the XML description) and129Updating the module (in order to load the XML description) and
138re-starting the server should display a new menu *Example Client130re-starting the server should display a new menu *Example Client
@@ -148,8 +140,7 @@
148its :js:func:`~openerp.web.Widget.start` to add some content to its140its :js:func:`~openerp.web.Widget.start` to add some content to its
149DOM:141DOM:
150142
151.. literalinclude:: module/static/src/js/first_module.js.3.diff143.. patch::
152 :language: diff
153144
154after reloading the client (to update the javascript file), instead of145after reloading the client (to update the javascript file), instead of
155printing to the console the menu item clears the whole screen and146printing to the console the menu item clears the whole screen and
@@ -159,15 +150,13 @@
159<widget-dom_root>` we can now see how to add a stylesheet to a module:150<widget-dom_root>` we can now see how to add a stylesheet to a module:
160first create the stylesheet file:151first create the stylesheet file:
161152
162.. literalinclude:: module/static/src/css/web_example.css153.. patch::
163 :language: css
164154
165then add a reference to the stylesheet in the module's manifest (which155then add a reference to the stylesheet in the module's manifest (which
166will require restarting the OpenERP Server to see the changes, as156will require restarting the OpenERP Server to see the changes, as
167usual):157usual):
168158
169.. literalinclude:: module/__openerp__.py.4.diff159.. patch::
170 :language: diff
171160
172the text displayed by the menu item should now be huge, and161the text displayed by the menu item should now be huge, and
173white-on-black (instead of small and black-on-white). From there on,162white-on-black (instead of small and black-on-white). From there on,
@@ -204,22 +193,16 @@
204193
205Adding a template file is similar to adding a style sheet:194Adding a template file is similar to adding a style sheet:
206195
207.. literalinclude:: module/static/src/xml/web_example.xml196.. patch::
208 :language: xml
209
210.. literalinclude:: module/__openerp__.py.5.diff
211 :language: diff
212197
213The template can then easily be hooked in the widget:198The template can then easily be hooked in the widget:
214199
215.. literalinclude:: module/static/src/js/first_module.js.4.diff200.. patch::
216 :language: diff
217201
218And finally the CSS can be altered to style the new (and more complex)202And finally the CSS can be altered to style the new (and more complex)
219template-generated DOM, rather than the code-generated one:203template-generated DOM, rather than the code-generated one:
220204
221.. literalinclude:: module/static/src/css/web_example.css.1.diff205.. patch::
222 :language: diff
223206
224.. note::207.. note::
225208
@@ -238,15 +221,13 @@
238our stopwatch watch. First hook some events on the buttons to toggle221our stopwatch watch. First hook some events on the buttons to toggle
239the widget's state:222the widget's state:
240223
241.. literalinclude:: module/static/src/js/first_module.js.5.diff224.. patch::
242 :language: diff
243225
244This demonstrates the use of the "events hash" and event delegation to226This demonstrates the use of the "events hash" and event delegation to
245declaratively handle events on the widget's DOM. And already changes227declaratively handle events on the widget's DOM. And already changes
246the button displayed in the UI. Then comes some actual logic:228the button displayed in the UI. Then comes some actual logic:
247229
248.. literalinclude:: module/static/src/js/first_module.js.6.diff230.. patch::
249 :language: diff
250231
251* An initializer (the ``init`` method) is introduced to set-up a few232* An initializer (the ``init`` method) is introduced to set-up a few
252 internal variables: ``_start`` will hold the start of the timer (as233 internal variables: ``_start`` will hold the start of the timer (as
@@ -273,6 +254,184 @@
273Starting and stopping the watch now works, and correctly tracks time254Starting and stopping the watch now works, and correctly tracks time
274since having started the watch, neatly formatted.255since having started the watch, neatly formatted.
275256
257Burning through the skies
258-------------------------
259
260All work so far has been "local" outside of the original impetus
261provided by the client action: the widget is self-contained and, once
262started, does not communicate with anything outside itself. Not only
263that, but it has no persistence: if the user leaves the stopwatch
264screen (to go and see his inbox, or do some well-deserved accounting,
265for instance) whatever was being timed will be lost.
266
267To prevent this irremediable loss, we can use OpenERP's support for
268storing data as a model, allowing so that we don't lose our data and
269can later retrieve, query and manipulate it. First let's create a
270basic OpenERP model in which our data will be stored:
271
272.. patch::
273
274then let's add saving times to the database every time the stopwatch
275is stopped, using :js:class:`the "high-level" Model API
276<openerp.web.Model.call>`:
277
278.. patch::
279
280A look at the "Network" tab of your preferred browser's developer
281tools while playing with the stopwatch will show that the save
282(creation) request is indeed sent (and replied to, even though we're
283ignoring the response at this point).
284
285These saved data should now be loaded and displayed when first opening
286the action, so the user can see his previously recorded times. This is
287done by overloading the model's ``start`` method: the purpose of
288:js:func:`~openerp.base.Widget.start()` is to perform *asynchronous*
289initialization steps, so the rest of the web client knows to "wait"
290and gets a readiness signal. In this case, it will fetch the data
291recorded previously using the :js:class:`~openerp.web.Query` interface
292and add this data to an ordered list added to the widget's template:
293
294.. patch::
295
296And for consistency's sake (so that the display a user leaves is
297pretty much the same as the one he comes back to), newly created
298records should also automatically be added to the list:
299
300.. patch::
301
302Note that we're only displaying the record once we know it's been
303saved from the database (the ``create`` call has returned without
304error).
305
306Mic check, is this working?
307---------------------------
308
309So far, features have been implemented, code has been worked and
310tentatively tried. However, there is no guarantee they will *keep
311working* as new changes are performed, new features added, …
312
313The original author (you, dear reader) could keep a notebook with a
314list of workflows to check, to ensure everything keeps working. And
315follow the notebook day after day, every time something is changed in
316the module.
317
318That gets repetitive after a while. And computers are good at doing
319repetitive stuff, as long as you tell them how to do it.
320
321So let's add test to the module, so that in the future the computer
322can take care of ensuring what works today keeps working tomorrow.
323
324.. note::
325
326 Here we're writing tests after having implemented the widget. This
327 may or may not work, we may need to alter bits and pieces of code
328 to get them in a testable state. An other testing methodology is
329 :abbr:`TDD (Test-Driven Development)` where the tests are written
330 first, and the code necessary to make these tests pass is written
331 afterwards.
332
333 Both methods have their opponents and detractors, advantages and
334 inconvenients. Pick the one you prefer.
335
336The first step of :doc:`testing` is to set up the basic testing
337structure:
338
3391. Creating a javascript file
340
341 .. patch::
342
3432. Containing a test section (and a few tests to make sure the tests
344 are correctly run)
345
346 .. patch::
347
3483. Then declaring the test file in the module's manifest
349
350 .. patch::
351
3524. And finally — after restarting OpenERP — navigating to the test
353 runner at ``/web/tests`` and selecting your soon-to-be-tested
354 module:
355
356 .. image:: module/testing_0.png
357 :align: center
358
359 the testing result do indeed match the test.
360
361The simplest tests to write are for synchronous pure
362functions. Synchronous means no RPC call or any other such thing
363(e.g. ``setTimeout``), only direct data processing, and pure means no
364side-effect: the function takes some input, manipulates it and yields
365an output.
366
367In our widget, only ``format_time`` fits the bill: it takes a duration
368(in milliseconds) and returns an ``hours:minutes:second`` formatting
369of it. Let's test it:
370
371.. patch::
372
373This series of simple tests passes with no issue. The next easy-ish
374test type is to test basic DOM alterations from provided input, such
375as (for our widget) updating the counter or displaying a record to the
376records list: while it's not pure (it alters the DOM "in-place") it
377has well-delimited side-effects and these side-effects come solely
378from the provided input.
379
380Because these methods alter the widget's DOM, the widget needs a
381DOM. Looking up :doc:`a widget's lifecycle <widget>`, the widget
382really only gets its DOM when adding it to the document. However a
383side-effect of this is to :js:func:`~openerp.web.Widget.start` it,
384which for us means going to query the user's times.
385
386We don't have any records to get in our test, and we don't want to
387test the initialization yet! So let's cheat a bit: we can manually
388:js:func:`set a widget's DOM <openerp.web.Widget.setElement>`, let's
389create a basic DOM matching what each method expects then call the
390method:
391
392.. patch::
393
394The next group of patches (in terms of setup/complexity) is RPC tests:
395testing components/methods which perform network calls (RPC
396requests). In our module, ``start`` and ``watch_stop`` are in that
397case: ``start`` fetches the user's recorded times and ``watch_stop``
398creates a new record with the current watch.
399
400By default, tests don't allow RPC requests and will generate an error
401when trying to perform one:
402
403.. image:: module/testing_1.png
404 :align: center
405
406To allow them, the test case (or the test suite) has to explicitly opt
407into :js:attr:`rpc support <TestOptions.rpc>` by adding the ``rpc:
408'mock'`` option to the test case, and providing its own "rpc
409responses":
410
411.. patch::
412
413.. note::
414
415 By defaut, tests cases don't load templates either. We had not
416 needed to perform any template rendering before here, so we must
417 now enable templates loading via :js:attr:`the corresponding
418 option <TestOptions.templates>`.
419
420Our final test requires altering the module's code: asynchronous tests
421use :doc:`deferred </async>` to know when a test ends and the other
422one can start (otherwise test content will execute non-linearly and
423the assertions of a test will be executed during the next test or
424worse), but although ``watch_stop`` performs an asynchronous
425``create`` operation it doesn't return a deferred we can synchronize
426on. We simply need to return its result:
427
428.. patch::
429
430This makes no difference to the original code, but allows us to write
431our test:
432
433.. patch::
434
276.. [#DOM-building] they are not alternative solutions: they work very435.. [#DOM-building] they are not alternative solutions: they work very
277 well together. Templates are used to build "just436 well together. Templates are used to build "just
278 DOM", sub-widgets are used to build DOM subsections437 DOM", sub-widgets are used to build DOM subsections
279438
=== added file 'addons/web/doc/module/0'
--- addons/web/doc/module/0 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/0 2013-02-18 15:08:21 +0000
@@ -0,0 +1,17 @@
1# HG changeset patch
2# Parent 0000000000000000000000000000000000000000
3
4diff --git a/__init__.py b/__init__.py
5new file mode 100644
6diff --git a/__openerp__.py b/__openerp__.py
7new file mode 100644
8--- /dev/null
9+++ b/__openerp__.py
10@@ -0,0 +1,7 @@
11+# __openerp__.py
12+{
13+ 'name': "Web Example",
14+ 'description': "Basic example of a (future) web module",
15+ 'category': 'Hidden',
16+ 'depends': ['base'],
17+}
018
=== added file 'addons/web/doc/module/10'
--- addons/web/doc/module/10 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/10 2013-02-18 15:08:21 +0000
@@ -0,0 +1,13 @@
1# HG changeset patch
2# Parent 72d9d59a93fcee06ba28cf0b98a1075331dcc8f4
3diff --git a/static/src/css/web_example.css b/static/src/css/web_example.css
4new file mode 100644
5--- /dev/null
6+++ b/static/src/css/web_example.css
7@@ -0,0 +1,6 @@
8+.openerp .oe_web_example {
9+ color: white;
10+ background-color: black;
11+ height: 100%;
12+ font-size: 400%;
13+}
014
=== added file 'addons/web/doc/module/11'
--- addons/web/doc/module/11 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/11 2013-02-18 15:08:21 +0000
@@ -0,0 +1,11 @@
1# HG changeset patch
2# Parent 3ed382d9a8fe64fbb8e2bf4045e3fcd5c74c92bc
3diff --git a/__openerp__.py b/__openerp__.py
4--- a/__openerp__.py
5+++ b/__openerp__.py
6@@ -6,4 +6,5 @@
7 'depends': ['web'],
8 'data': ['web_example.xml'],
9 'js': ['static/src/js/first_module.js'],
10+ 'css': ['static/src/css/web_example.css'],
11 }
012
=== added file 'addons/web/doc/module/12'
--- addons/web/doc/module/12 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/12 2013-02-18 15:08:21 +0000
@@ -0,0 +1,28 @@
1# HG changeset patch
2# Parent 43f21611dacb7c2b2f3810baeeef359ad7c329f0
3
4diff --git a/__openerp__.py b/__openerp__.py
5--- a/__openerp__.py
6+++ b/__openerp__.py
7@@ -7,4 +7,5 @@
8 'data': ['web_example.xml'],
9 'js': ['static/src/js/first_module.js'],
10 'css': ['static/src/css/web_example.css'],
11+ 'qweb': ['static/src/xml/web_example.xml'],
12 }
13diff --git a/static/src/xml/web_example.xml b/static/src/xml/web_example.xml
14new file mode 100644
15--- /dev/null
16+++ b/static/src/xml/web_example.xml
17@@ -0,0 +1,11 @@
18+<templates>
19+<div t-name="web_example.action" class="oe_web_example oe_web_example_stopped">
20+ <h4 class="oe_web_example_timer">00:00:00</h4>
21+ <p class="oe_web_example_start">
22+ <button type="button">Start</button>
23+ </p>
24+ <p class="oe_web_example_stop">
25+ <button type="button">Stop</button>
26+ </p>
27+</div>
28+</templates>
029
=== added file 'addons/web/doc/module/14'
--- addons/web/doc/module/14 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/14 2013-02-18 15:08:21 +0000
@@ -0,0 +1,17 @@
1# HG changeset patch
2# Parent ae3b427c96b532794a65357b3f075129cc991276
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -2,10 +2,6 @@
7 openerp.web_example = function (instance) {
8 instance.web.client_actions.add('example.action', 'instance.web_example.Action');
9 instance.web_example.Action = instance.web.Widget.extend({
10- className: 'oe_web_example',
11- start: function () {
12- this.$el.text("Hello, world!");
13- return this._super();
14- }
15+ template: 'web_example.action'
16 });
17 };
018
=== added file 'addons/web/doc/module/15'
--- addons/web/doc/module/15 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/15 2013-02-18 15:08:21 +0000
@@ -0,0 +1,19 @@
1# HG changeset patch
2# Parent e2d2e1a4cc2d2496aebeb05d94768384427c9e8b
3diff --git a/static/src/css/web_example.css b/static/src/css/web_example.css
4--- a/static/src/css/web_example.css
5+++ b/static/src/css/web_example.css
6@@ -2,5 +2,12 @@
7 color: white;
8 background-color: black;
9 height: 100%;
10- font-size: 400%;
11 }
12+.openerp .oe_web_example h4 {
13+ margin: 0;
14+ font-size: 200%;
15+}
16+.openerp .oe_web_example.oe_web_example_started .oe_web_example_start button,
17+.openerp .oe_web_example.oe_web_example_stopped .oe_web_example_stop button {
18+ display: none
19+}
020
=== added file 'addons/web/doc/module/16'
--- addons/web/doc/module/16 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/16 2013-02-18 15:08:21 +0000
@@ -0,0 +1,25 @@
1# HG changeset patch
2# Parent 2645d7a09dcba7f6d6074a33252c16c03c56fdf3
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -2,6 +2,18 @@
7 openerp.web_example = function (instance) {
8 instance.web.client_actions.add('example.action', 'instance.web_example.Action');
9 instance.web_example.Action = instance.web.Widget.extend({
10- template: 'web_example.action'
11+ template: 'web_example.action',
12+ events: {
13+ 'click .oe_web_example_start button': 'watch_start',
14+ 'click .oe_web_example_stop button': 'watch_stop'
15+ },
16+ watch_start: function () {
17+ this.$el.addClass('oe_web_example_started')
18+ .removeClass('oe_web_example_stopped');
19+ },
20+ watch_stop: function () {
21+ this.$el.removeClass('oe_web_example_started')
22+ .addClass('oe_web_example_stopped');
23+ },
24 });
25 };
026
=== added file 'addons/web/doc/module/17'
--- addons/web/doc/module/17 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/17 2013-02-18 15:08:21 +0000
@@ -0,0 +1,52 @@
1# HG changeset patch
2# Parent 2921a545adc3406d3139be7951f3225e94493466
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -7,13 +7,46 @@ openerp.web_example = function (instance
7 'click .oe_web_example_start button': 'watch_start',
8 'click .oe_web_example_stop button': 'watch_stop'
9 },
10+ init: function () {
11+ this._super.apply(this, arguments);
12+ this._start = null;
13+ this._watch = null;
14+ },
15+ update_counter: function () {
16+ var h, m, s;
17+ // Subtracting javascript dates returns the difference in milliseconds
18+ var diff = new Date() - this._start;
19+ s = diff / 1000;
20+ m = Math.floor(s / 60);
21+ s -= 60*m;
22+ h = Math.floor(m / 60);
23+ m -= 60*h;
24+ this.$('.oe_web_example_timer').text(
25+ _.str.sprintf("%02d:%02d:%02d", h, m, s));
26+ },
27 watch_start: function () {
28 this.$el.addClass('oe_web_example_started')
29 .removeClass('oe_web_example_stopped');
30+ this._start = new Date();
31+ // Update the UI to the current time
32+ this.update_counter();
33+ // Update the counter at 30 FPS (33ms/frame)
34+ this._watch = setInterval(
35+ this.proxy('update_counter'),
36+ 33);
37 },
38 watch_stop: function () {
39+ clearInterval(this._watch);
40+ this.update_counter();
41+ this._start = this._watch = null;
42 this.$el.removeClass('oe_web_example_started')
43 .addClass('oe_web_example_stopped');
44 },
45+ destroy: function () {
46+ if (this._watch) {
47+ clearInterval(this._watch);
48+ }
49+ this._super();
50+ }
51 });
52 };
053
=== added file 'addons/web/doc/module/18'
--- addons/web/doc/module/18 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/18 2013-02-18 15:08:21 +0000
@@ -0,0 +1,19 @@
1# HG changeset patch
2# Parent e0cc13c2b2ec4d6f6bfdb033b189a32e44106f2e
3diff --git a/__init__.py b/__init__.py
4--- a/__init__.py
5+++ b/__init__.py
6@@ -0,0 +1,13 @@
7+# __init__.py
8+from openerp.osv import orm, fields
9+
10+
11+class Times(orm.Model):
12+ _name = 'web_example.stopwatch'
13+
14+ _columns = {
15+ 'time': fields.integer("Time", required=True,
16+ help="Measured time in milliseconds"),
17+ 'user_id': fields.many2one('res.users', "User", required=True,
18+ help="User who registered the measurement")
19+ }
020
=== added file 'addons/web/doc/module/19'
--- addons/web/doc/module/19 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/19 2013-02-18 15:08:21 +0000
@@ -0,0 +1,52 @@
1# HG changeset patch
2# Parent 05797cc75b49634e640f44b24347f2905b464022
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -12,11 +12,13 @@ openerp.web_example = function (instance
7 this._start = null;
8 this._watch = null;
9 },
10- update_counter: function () {
11+ current: function () {
12+ // Subtracting javascript dates returns the difference in milliseconds
13+ return new Date() - this._start;
14+ },
15+ update_counter: function (time) {
16 var h, m, s;
17- // Subtracting javascript dates returns the difference in milliseconds
18- var diff = new Date() - this._start;
19- s = diff / 1000;
20+ s = time / 1000;
21 m = Math.floor(s / 60);
22 s -= 60*m;
23 h = Math.floor(m / 60);
24@@ -29,18 +31,24 @@ openerp.web_example = function (instance
25 .removeClass('oe_web_example_stopped');
26 this._start = new Date();
27 // Update the UI to the current time
28- this.update_counter();
29+ this.update_counter(this.current());
30 // Update the counter at 30 FPS (33ms/frame)
31- this._watch = setInterval(
32- this.proxy('update_counter'),
33+ this._watch = setInterval(function () {
34+ this.update_counter(this.current());
35+ }.bind(this),
36 33);
37 },
38 watch_stop: function () {
39 clearInterval(this._watch);
40- this.update_counter();
41+ var time = this.current();
42+ this.update_counter(time);
43 this._start = this._watch = null;
44 this.$el.removeClass('oe_web_example_started')
45 .addClass('oe_web_example_stopped');
46+ new instance.web.Model('web_example.stopwatch').call('create', [{
47+ user_id: instance.session.uid,
48+ time: time,
49+ }]);
50 },
51 destroy: function () {
52 if (this._watch) {
053
=== added file 'addons/web/doc/module/2'
--- addons/web/doc/module/2 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/2 2013-02-18 15:08:21 +0000
@@ -0,0 +1,12 @@
1# HG changeset patch
2# Parent 8a986919a3e22cd7cca51210820c09d4545dc60d
3diff --git a/__openerp__.py b/__openerp__.py
4--- a/__openerp__.py
5+++ b/__openerp__.py
6@@ -3,5 +3,5 @@
7 'name': "Web Example",
8 'description': "Basic example of a (future) web module",
9 'category': 'Hidden',
10- 'depends': ['base'],
11+ 'depends': ['web'],
12 }
013
=== added file 'addons/web/doc/module/20'
--- addons/web/doc/module/20 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/20 2013-02-18 15:08:21 +0000
@@ -0,0 +1,64 @@
1Index: web_example/static/src/js/first_module.js
2===================================================================
3--- web_example.orig/static/src/js/first_module.js
4+++ web_example/static/src/js/first_module.js
5@@ -11,20 +11,36 @@ openerp.web_example = function (instance
6 this._super.apply(this, arguments);
7 this._start = null;
8 this._watch = null;
9+ this.model = new instance.web.Model('web_example.stopwatch');
10+ },
11+ start: function () {
12+ var display = this.display_record.bind(this);
13+ return this.model.query()
14+ .filter([['user_id', '=', instance.session.uid]])
15+ .all().done(function (records) {
16+ _(records).each(display);
17+ });
18 },
19 current: function () {
20 // Subtracting javascript dates returns the difference in milliseconds
21 return new Date() - this._start;
22 },
23- update_counter: function (time) {
24+ display_record: function (record) {
25+ $('<li>')
26+ .text(this.format_time(record.time))
27+ .appendTo(this.$('.oe_web_example_saved'));
28+ },
29+ format_time: function (time) {
30 var h, m, s;
31 s = time / 1000;
32 m = Math.floor(s / 60);
33 s -= 60*m;
34 h = Math.floor(m / 60);
35 m -= 60*h;
36- this.$('.oe_web_example_timer').text(
37- _.str.sprintf("%02d:%02d:%02d", h, m, s));
38+ return _.str.sprintf("%02d:%02d:%02d", h, m, s);
39+ },
40+ update_counter: function (time) {
41+ this.$('.oe_web_example_timer').text(this.format_time(time));
42 },
43 watch_start: function () {
44 this.$el.addClass('oe_web_example_started')
45@@ -45,7 +61,7 @@ openerp.web_example = function (instance
46 this._start = this._watch = null;
47 this.$el.removeClass('oe_web_example_started')
48 .addClass('oe_web_example_stopped');
49- new instance.web.Model('web_example.stopwatch').call('create', [{
50+ this.model.call('create', [{
51 user_id: instance.session.uid,
52 time: time,
53 }]);
54Index: web_example/static/src/xml/web_example.xml
55===================================================================
56--- web_example.orig/static/src/xml/web_example.xml
57+++ web_example/static/src/xml/web_example.xml
58@@ -7,5 +7,6 @@
59 <p class="oe_web_example_stop">
60 <button type="button">Stop</button>
61 </p>
62+ <ol class="oe_web_example_saved"></ol>
63 </div>
64 </templates>
065
=== added file 'addons/web/doc/module/21'
--- addons/web/doc/module/21 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/21 2013-02-18 15:08:21 +0000
@@ -0,0 +1,27 @@
1Index: web_example/static/src/js/first_module.js
2===================================================================
3--- web_example.orig/static/src/js/first_module.js
4+++ web_example/static/src/js/first_module.js
5@@ -55,16 +55,20 @@ openerp.web_example = function (instance
6 33);
7 },
8 watch_stop: function () {
9+ var self = this;
10 clearInterval(this._watch);
11 var time = this.current();
12 this.update_counter(time);
13 this._start = this._watch = null;
14 this.$el.removeClass('oe_web_example_started')
15 .addClass('oe_web_example_stopped');
16- this.model.call('create', [{
17+ var record = {
18 user_id: instance.session.uid,
19 time: time,
20- }]);
21+ };
22+ this.model.call('create', [record]).done(function () {
23+ self.display_record(record);
24+ });
25 },
26 destroy: function () {
27 if (this._watch) {
028
=== added file 'addons/web/doc/module/22'
--- addons/web/doc/module/22 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/22 2013-02-18 15:08:21 +0000
@@ -0,0 +1,6 @@
1Index: web_example/static/src/tests/timer.js
2===================================================================
3--- /dev/null
4+++ web_example/static/src/tests/timer.js
5@@ -0,0 +1 @@
6+
07
=== added file 'addons/web/doc/module/23'
--- addons/web/doc/module/23 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/23 2013-02-18 15:08:21 +0000
@@ -0,0 +1,14 @@
1Index: web_example/static/src/tests/timer.js
2===================================================================
3--- web_example.orig/static/src/tests/timer.js
4+++ web_example/static/src/tests/timer.js
5@@ -1 +1,8 @@
6-
7+openerp.testing.section('timer', function (test) {
8+ test('successful test', function () {
9+ ok(true, "should work");
10+ });
11+ test('unsuccessful test', function () {
12+ ok(false, "shoud fail");
13+ });
14+});
015
=== added file 'addons/web/doc/module/24'
--- addons/web/doc/module/24 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/24 2013-02-18 15:08:21 +0000
@@ -0,0 +1,10 @@
1Index: web_example/__openerp__.py
2===================================================================
3--- web_example.orig/__openerp__.py
4+++ web_example/__openerp__.py
5@@ -8,4 +8,5 @@
6 'js': ['static/src/js/first_module.js'],
7 'css': ['static/src/css/web_example.css'],
8 'qweb': ['static/src/xml/web_example.xml'],
9+ 'test': ['static/src/tests/timer.js'],
10 }
011
=== added file 'addons/web/doc/module/25'
--- addons/web/doc/module/25 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/25 2013-02-18 15:08:21 +0000
@@ -0,0 +1,55 @@
1Index: web_example/static/src/tests/timer.js
2===================================================================
3--- web_example.orig/static/src/tests/timer.js
4+++ web_example/static/src/tests/timer.js
5@@ -1,8 +1,45 @@
6 openerp.testing.section('timer', function (test) {
7- test('successful test', function () {
8- ok(true, "should work");
9- });
10- test('unsuccessful test', function () {
11- ok(false, "shoud fail");
12+ test('format_time', function (instance) {
13+ var w = new instance.web_example.Action();
14+
15+ strictEqual(
16+ w.format_time(0),
17+ '00:00:00');
18+ strictEqual(
19+ w.format_time(543),
20+ '00:00:00',
21+ "should round sub-second times down to zero");
22+ strictEqual(
23+ w.format_time(5340),
24+ '00:00:05',
25+ "should floor sub-second extents to the previous second");
26+ strictEqual(
27+ w.format_time(60000),
28+ '00:01:00');
29+ strictEqual(
30+ w.format_time(3600000),
31+ '01:00:00');
32+ strictEqual(
33+ w.format_time(86400000),
34+ '24:00:00');
35+ strictEqual(
36+ w.format_time(604800000),
37+ '168:00:00');
38+
39+ strictEqual(
40+ w.format_time(22733958),
41+ '06:18:53');
42+ strictEqual(
43+ w.format_time(41676639),
44+ '11:34:36');
45+ strictEqual(
46+ w.format_time(57802094),
47+ '16:03:22');
48+ strictEqual(
49+ w.format_time(73451828),
50+ '20:24:11');
51+ strictEqual(
52+ w.format_time(84092336),
53+ '23:21:32');
54 });
55 });
056
=== added file 'addons/web/doc/module/26'
--- addons/web/doc/module/26 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/26 2013-02-18 15:08:21 +0000
@@ -0,0 +1,38 @@
1Index: web_example/static/src/tests/timer.js
2===================================================================
3--- web_example.orig/static/src/tests/timer.js
4+++ web_example/static/src/tests/timer.js
5@@ -42,4 +42,33 @@ openerp.testing.section('timer', functio
6 w.format_time(84092336),
7 '23:21:32');
8 });
9+ test('update_counter', function (instance, $fixture) {
10+ var w = new instance.web_example.Action();
11+ // $fixture is a DOM tree whose content gets cleaned up before
12+ // each test, so we can add whatever we need to it
13+ $fixture.append('<div class="oe_web_example_timer">');
14+ // Then set it on the widget
15+ w.setElement($fixture);
16+
17+ // Update the counter with a known value
18+ w.update_counter(22733958);
19+ // And check the DOM matches
20+ strictEqual($fixture.text(), '06:18:53');
21+
22+ w.update_counter(73451828)
23+ strictEqual($fixture.text(), '20:24:11');
24+ });
25+ test('display_record', function (instance, $fixture) {
26+ var w = new instance.web_example.Action();
27+ $fixture.append('<ol class="oe_web_example_saved">')
28+ w.setElement($fixture);
29+
30+ w.display_record({time: 41676639});
31+ w.display_record({time: 84092336});
32+
33+ var $lis = $fixture.find('li');
34+ strictEqual($lis.length, 2, "should have printed 2 records");
35+ strictEqual($lis[0].textContent, '11:34:36');
36+ strictEqual($lis[1].textContent, '23:21:32');
37+ });
38 });
039
=== added file 'addons/web/doc/module/27'
--- addons/web/doc/module/27 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/27 2013-02-18 15:08:21 +0000
@@ -0,0 +1,28 @@
1Index: web_example/static/src/tests/timer.js
2===================================================================
3--- web_example.orig/static/src/tests/timer.js
4+++ web_example/static/src/tests/timer.js
5@@ -71,4 +71,23 @@ openerp.testing.section('timer', functio
6 strictEqual($lis[0].textContent, '11:34:36');
7 strictEqual($lis[1].textContent, '23:21:32');
8 });
9+ test('start', {templates: true, rpc: 'mock', asserts: 3}, function (instance, $fixture, mock) {
10+ // Rather odd-looking shortcut for search+read in a single RPC call
11+ mock('/web/dataset/search_read', function () {
12+ // ignore parameters, just return a pair of records.
13+ return {records: [
14+ {time: 22733958},
15+ {time: 84092336}
16+ ]};
17+ });
18+
19+ var w = new instance.web_example.Action();
20+ return w.appendTo($fixture)
21+ .then(function () {
22+ var $lis = $fixture.find('li');
23+ strictEqual($lis.length, 2);
24+ strictEqual($lis[0].textContent, '06:18:53');
25+ strictEqual($lis[1].textContent, '23:21:32');
26+ });
27+ });
28 });
029
=== added file 'addons/web/doc/module/28'
--- addons/web/doc/module/28 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/28 2013-02-18 15:08:21 +0000
@@ -0,0 +1,13 @@
1Index: web_example/static/src/js/first_module.js
2===================================================================
3--- web_example.orig/static/src/js/first_module.js
4+++ web_example/static/src/js/first_module.js
5@@ -66,7 +66,7 @@ openerp.web_example = function (instance
6 user_id: instance.session.uid,
7 time: time,
8 };
9- this.model.call('create', [record]).done(function () {
10+ return this.model.call('create', [record]).done(function () {
11 self.display_record(record);
12 });
13 },
014
=== added file 'addons/web/doc/module/29'
--- addons/web/doc/module/29 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/29 2013-02-18 15:08:21 +0000
@@ -0,0 +1,37 @@
1Index: web_example/static/src/tests/timer.js
2===================================================================
3--- web_example.orig/static/src/tests/timer.js
4+++ web_example/static/src/tests/timer.js
5@@ -90,4 +90,32 @@ openerp.testing.section('timer', functio
6 strictEqual($lis[1].textContent, '23:21:32');
7 });
8 });
9+ test('watch_stop', {templates: true, rpc: 'mock', asserts: 3}, function (instance, $fix, mock) {
10+ var created = false;
11+ mock('web_example.stopwatch:create', function (args, kwargs) {
12+ created = true;
13+ // return a fake id (unused)
14+ return 42;
15+ });
16+ mock('/web/dataset/search_read', function () {
17+ return {records: []};
18+ });
19+
20+ var w = new instance.web_example.Action();
21+ return w.appendTo($fix)
22+ .then(function () {
23+ // Virtual start point 5s before 'now'
24+ w._start = new Date() - 5000;
25+ return w.watch_stop();
26+ })
27+ .done(function () {
28+ ok(created, "should have called create()");
29+ strictEqual($fix.find('.oe_web_example_timer').text(),
30+ '00:00:05',
31+ "should have updated the timer");
32+ strictEqual($fix.find('li')[0].textContent,
33+ '00:00:05',
34+ "should have added the new time to the list");
35+ });
36+ });
37 });
038
=== added file 'addons/web/doc/module/3'
--- addons/web/doc/module/3 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/3 2013-02-18 15:08:21 +0000
@@ -0,0 +1,9 @@
1# HG changeset patch
2# Parent dcf661a5eef8f82503831bdb8e6c9d2f9beb285e
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4new file mode 100644
5--- /dev/null
6+++ b/static/src/js/first_module.js
7@@ -0,0 +1,2 @@
8+// static/src/js/first_module.js
9+console.log("Debug statement: file loaded");
010
=== added file 'addons/web/doc/module/4'
--- addons/web/doc/module/4 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/4 2013-02-18 15:08:21 +0000
@@ -0,0 +1,11 @@
1# HG changeset patch
2# Parent 139dae60de67efa0017f5032f71ab774685c5507
3diff --git a/__openerp__.py b/__openerp__.py
4--- a/__openerp__.py
5+++ b/__openerp__.py
6@@ -4,4 +4,5 @@
7 'description': "Basic example of a (future) web module",
8 'category': 'Hidden',
9 'depends': ['web'],
10+ 'js': ['static/src/js/first_module.js'],
11 }
012
=== added file 'addons/web/doc/module/5'
--- addons/web/doc/module/5 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/5 2013-02-18 15:08:21 +0000
@@ -0,0 +1,11 @@
1# HG changeset patch
2# Parent c8ae7646cce3f271698c844eb2d67f9a8719650d
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -1,2 +1,4 @@
7 // static/src/js/first_module.js
8-console.log("Debug statement: file loaded");
9+openerp.web_example = function (instance) {
10+ console.log("Module loaded");
11+};
012
=== added file 'addons/web/doc/module/6'
--- addons/web/doc/module/6 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/6 2013-02-18 15:08:21 +0000
@@ -0,0 +1,29 @@
1# HG changeset patch
2# Parent 0026cb80097a724db8d36371bc00da993a51a06f
3
4diff --git a/__openerp__.py b/__openerp__.py
5--- a/__openerp__.py
6+++ b/__openerp__.py
7@@ -4,5 +4,6 @@
8 'description': "Basic example of a (future) web module",
9 'category': 'Hidden',
10 'depends': ['web'],
11+ 'data': ['web_example.xml'],
12 'js': ['static/src/js/first_module.js'],
13 }
14diff --git a/web_example.xml b/web_example.xml
15new file mode 100644
16--- /dev/null
17+++ b/web_example.xml
18@@ -0,0 +1,11 @@
19+<!-- web_example/web_example.xml -->
20+<openerp>
21+ <data>
22+ <record model="ir.actions.client" id="action_client_example">
23+ <field name="name">Example Client Action</field>
24+ <field name="tag">example.action</field>
25+ </record>
26+ <menuitem action="action_client_example"
27+ id="menu_client_example"/>
28+ </data>
29+</openerp>
030
=== added file 'addons/web/doc/module/8'
--- addons/web/doc/module/8 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/8 2013-02-18 15:08:21 +0000
@@ -0,0 +1,14 @@
1# HG changeset patch
2# Parent d987c9edd884de1de30f2ceb70d2e554474b8dd1
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -1,4 +1,7 @@
7 // static/src/js/first_module.js
8 openerp.web_example = function (instance) {
9- console.log("Module loaded");
10+ instance.web.client_actions.add('example.action', 'instance.web_example.action');
11+ instance.web_example.action = function (parent, action) {
12+ console.log("Executed the action", action);
13+ };
14 };
015
=== added file 'addons/web/doc/module/9'
--- addons/web/doc/module/9 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/9 2013-02-18 15:08:21 +0000
@@ -0,0 +1,21 @@
1# HG changeset patch
2# Parent 6a1a7240ea0e63182f60abb1eb5c631089d56dbe
3diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js
4--- a/static/src/js/first_module.js
5+++ b/static/src/js/first_module.js
6@@ -1,7 +1,11 @@
7 // static/src/js/first_module.js
8 openerp.web_example = function (instance) {
9- instance.web.client_actions.add('example.action', 'instance.web_example.action');
10- instance.web_example.action = function (parent, action) {
11- console.log("Executed the action", action);
12- };
13+ instance.web.client_actions.add('example.action', 'instance.web_example.Action');
14+ instance.web_example.Action = instance.web.Widget.extend({
15+ className: 'oe_web_example',
16+ start: function () {
17+ this.$el.text("Hello, world!");
18+ return this._super();
19+ }
20+ });
21 };
022
=== removed file 'addons/web/doc/module/__init__.py'
=== removed file 'addons/web/doc/module/__openerp__.py'
--- addons/web/doc/module/__openerp__.py 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/__openerp__.py 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
1# __openerp__.py
2{
3 'name': "Web Example",
4 'description': "Basic example of a (future) web module",
5 'category': 'Hidden',
6 'depends': ['base'],
7}
80
=== removed file 'addons/web/doc/module/__openerp__.py.1.diff'
--- addons/web/doc/module/__openerp__.py.1.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/__openerp__.py.1.diff 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1--- web_example/__openerp__.py
2+++ web_example/__openerp__.py
3@@ -1,7 +1,7 @@
4 # __openerp__.py
5 {
6 'name': "Web Example",
7 'description': "Basic example of a (future) web module",
8 'category': 'Hidden',
9- 'depends': ['base'],
10+ 'depends': ['web'],
11 }
120
=== removed file 'addons/web/doc/module/__openerp__.py.2.diff'
--- addons/web/doc/module/__openerp__.py.2.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/__openerp__.py.2.diff 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1--- web_example/__openerp__.py
2+++ web_example/__openerp__.py
3@@ -1,7 +1,8 @@
4 # __openerp__.py
5 {
6 'name': "Web Example",
7 'description': "Basic example of a (future) web module",
8 'category': 'Hidden',
9 'depends': ['web'],
10+ 'js': ['static/src/js/first_module.js'],
11 }
120
=== removed file 'addons/web/doc/module/__openerp__.py.3.diff'
--- addons/web/doc/module/__openerp__.py.3.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/__openerp__.py.3.diff 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1--- web_example/__openerp__.py
2+++ web_example/__openerp__.py
3@@ -1,8 +1,9 @@
4 # __openerp__.py
5 {
6 'name': "Web Example",
7 'description': "Basic example of a (future) web module",
8 'category': 'Hidden',
9 'depends': ['web'],
10+ 'data': ['web_example.xml'],
11 'js': ['static/src/js/first_module.js'],
12 }
130
=== removed file 'addons/web/doc/module/__openerp__.py.4.diff'
--- addons/web/doc/module/__openerp__.py.4.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/__openerp__.py.4.diff 1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
1--- web_example/__openerp__.py
2+++ web_example/__openerp__.py
3@@ -1,9 +1,10 @@
4 # __openerp__.py
5 {
6 'name': "Web Example",
7 'description': "Basic example of a (future) web module",
8 'category': 'Hidden',
9 'depends': ['web'],
10 'data': ['web_example.xml'],
11 'js': ['static/src/js/first_module.js'],
12+ 'css': ['static/src/css/web_example.css'],
13 }
140
=== removed file 'addons/web/doc/module/__openerp__.py.5.diff'
--- addons/web/doc/module/__openerp__.py.5.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/__openerp__.py.5.diff 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1--- web_example/__openerp__.py
2+++ web_example/__openerp__.py
3@@ -1,10 +1,11 @@
4 # __openerp__.py
5 {
6 'name': "Web Example",
7 'description': "Basic example of a (future) web module",
8 'category': 'Hidden',
9 'depends': ['web'],
10 'data': ['web_example.xml'],
11 'js': ['static/src/js/first_module.js'],
12 'css': ['static/src/css/web_example.css'],
13+ 'qweb': ['static/src/xml/web_example.xml'],
14 }
150
=== added file 'addons/web/doc/module/series'
--- addons/web/doc/module/series 1970-01-01 00:00:00 +0000
+++ addons/web/doc/module/series 2013-02-18 15:08:21 +0000
@@ -0,0 +1,27 @@
10
22
33
44
55
66
78
89
910
1011
1112
1214
1315
1416
1517
1618
1719
1820
1921
2022
2123
2224
2325
2426
2527
2628
2729
028
=== removed directory 'addons/web/doc/module/static'
=== removed directory 'addons/web/doc/module/static/src'
=== removed directory 'addons/web/doc/module/static/src/css'
=== removed file 'addons/web/doc/module/static/src/css/web_example.css'
--- addons/web/doc/module/static/src/css/web_example.css 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/css/web_example.css 1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
1.openerp .oe_web_example {
2 color: white;
3 background-color: black;
4 height: 100%;
5 font-size: 400%;
6}
70
=== removed file 'addons/web/doc/module/static/src/css/web_example.css.1.diff'
--- addons/web/doc/module/static/src/css/web_example.css.1.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/css/web_example.css.1.diff 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
1--- web_example/static/src/css/web_example.css
2+++ web_example/static/src/css/web_example.css
3@@ -1,6 +1,13 @@
4 .openerp .oe_web_example {
5 color: white;
6 background-color: black;
7 height: 100%;
8- font-size: 400%;
9 }
10+.openerp .oe_web_example h4 {
11+ margin: 0;
12+ font-size: 200%;
13+}
14+.openerp .oe_web_example.oe_web_example_started .oe_web_example_start button,
15+.openerp .oe_web_example.oe_web_example_stopped .oe_web_example_stop button {
16+ display: none
17+}
180
=== removed directory 'addons/web/doc/module/static/src/js'
=== removed file 'addons/web/doc/module/static/src/js/first_module.js'
--- addons/web/doc/module/static/src/js/first_module.js 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
1// static/src/js/first_module.js
2console.log("Debug statement: file loaded");
30
=== removed file 'addons/web/doc/module/static/src/js/first_module.js.1.diff'
--- addons/web/doc/module/static/src/js/first_module.js.1.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js.1.diff 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1--- web_example/static/src/js/first_module.js
2+++ web_example/static/src/js/first_module.js
3@@ -1,2 +1,4 @@
4 // static/src/js/first_module.js
5-console.log("Debug statement: file loaded");
6+openerp.web_example = function (instance) {
7+ console.log("Module loaded");
8+};
90
=== removed file 'addons/web/doc/module/static/src/js/first_module.js.2.diff'
--- addons/web/doc/module/static/src/js/first_module.js.2.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js.2.diff 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1--- web_example/static/src/js/first_module.js
2+++ web_example/static/src/js/first_module.js
3@@ -1,4 +1,7 @@
4 // static/src/js/first_module.js
5 openerp.web_example = function (instance) {
6- console.log("Module loaded");
7+ instance.web.client_actions.add('example.action', 'instance.web_example.action');
8+ instance.web_example.action = function (parent, action) {
9+ console.log("Executed the action", action);
10+ };
11 };
120
=== removed file 'addons/web/doc/module/static/src/js/first_module.js.3.diff'
--- addons/web/doc/module/static/src/js/first_module.js.3.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js.3.diff 1970-01-01 00:00:00 +0000
@@ -1,18 +0,0 @@
1--- web_example/static/src/js/first_module.js
2+++ web_example/static/src/js/first_module.js
3@@ -1,7 +1,11 @@
4 // static/src/js/first_module.js
5 openerp.web_example = function (instance) {
6- instance.web.client_actions.add('example.action', 'instance.web_example.action');
7- instance.web_example.action = function (parent, action) {
8- console.log("Executed the action", action);
9- };
10+ instance.web.client_actions.add('example.action', 'instance.web_example.Action');
11+ instance.web_example.Action = instance.web.Widget.extend({
12+ className: 'oe_web_example',
13+ start: function () {
14+ this.$el.text("Hello, world!");
15+ return this._super();
16+ }
17+ });
18 };
190
=== removed file 'addons/web/doc/module/static/src/js/first_module.js.4.diff'
--- addons/web/doc/module/static/src/js/first_module.js.4.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js.4.diff 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
1--- web_example/static/src/js/first_module.js
2+++ web_example/static/src/js/first_module.js
3@@ -1,11 +1,7 @@
4 // static/src/js/first_module.js
5 openerp.web_example = function (instance) {
6 instance.web.client_actions.add('example.action', 'instance.web_example.Action');
7 instance.web_example.Action = instance.web.Widget.extend({
8+ template: 'web_example.action'
9- className: 'oe_web_example',
10- start: function () {
11- this.$el.text("Hello, world!");
12- return this._super();
13- }
14 });
15 };
160
=== removed file 'addons/web/doc/module/static/src/js/first_module.js.5.diff'
--- addons/web/doc/module/static/src/js/first_module.js.5.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js.5.diff 1970-01-01 00:00:00 +0000
@@ -1,23 +0,0 @@
1--- web_example/static/src/js/first_module.js
2+++ web_example/static/src/js/first_module.js
3@@ -1,7 +1,19 @@
4 // static/src/js/first_module.js
5 openerp.web_example = function (instance) {
6 instance.web.client_actions.add('example.action', 'instance.web_example.Action');
7 instance.web_example.Action = instance.web.Widget.extend({
8- template: 'web_example.action'
9+ template: 'web_example.action',
10+ events: {
11+ 'click .oe_web_example_start button': 'watch_start',
12+ 'click .oe_web_example_stop button': 'watch_stop'
13+ },
14+ watch_start: function () {
15+ this.$el.addClass('oe_web_example_started')
16+ .removeClass('oe_web_example_stopped');
17+ },
18+ watch_stop: function () {
19+ this.$el.removeClass('oe_web_example_started')
20+ .addClass('oe_web_example_stopped');
21+ },
22 });
23 };
240
=== removed file 'addons/web/doc/module/static/src/js/first_module.js.6.diff'
--- addons/web/doc/module/static/src/js/first_module.js.6.diff 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/js/first_module.js.6.diff 1970-01-01 00:00:00 +0000
@@ -1,55 +0,0 @@
1--- web_example/static/src/js/first_module.js
2+++ web_example/static/src/js/first_module.js
3@@ -1,19 +1,52 @@
4 // static/src/js/first_module.js
5 openerp.web_example = function (instance) {
6 instance.web.client_actions.add('example.action', 'instance.web_example.Action');
7 instance.web_example.Action = instance.web.Widget.extend({
8 template: 'web_example.action',
9 events: {
10 'click .oe_web_example_start button': 'watch_start',
11 'click .oe_web_example_stop button': 'watch_stop'
12 },
13+ init: function () {
14+ this._super.apply(this, arguments);
15+ this._start = null;
16+ this._watch = null;
17+ },
18+ update_counter: function () {
19+ var h, m, s;
20+ // Subtracting javascript dates returns the difference in milliseconds
21+ var diff = new Date() - this._start;
22+ s = diff / 1000;
23+ m = Math.floor(s / 60);
24+ s -= 60*m;
25+ h = Math.floor(m / 60);
26+ m -= 60*h;
27+ this.$('.oe_web_example_timer').text(
28+ _.str.sprintf("%02d:%02d:%02d", h, m, s));
29+ },
30 watch_start: function () {
31 this.$el.addClass('oe_web_example_started')
32 .removeClass('oe_web_example_stopped');
33+ this._start = new Date();
34+ // Update the UI to the current time
35+ this.update_counter();
36+ // Update the counter at 30 FPS (33ms/frame)
37+ this._watch = setInterval(
38+ this.proxy('update_counter'),
39+ 33);
40 },
41 watch_stop: function () {
42+ clearInterval(this._watch);
43+ this.update_counter();
44+ this._start = this._watch = null;
45 this.$el.removeClass('oe_web_example_started')
46 .addClass('oe_web_example_stopped');
47 },
48+ destroy: function () {
49+ if (this._watch) {
50+ clearInterval(this._watch);
51+ }
52+ this._super();
53+ }
54 });
55 };
560
=== removed directory 'addons/web/doc/module/static/src/xml'
=== removed file 'addons/web/doc/module/static/src/xml/web_example.xml'
--- addons/web/doc/module/static/src/xml/web_example.xml 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/static/src/xml/web_example.xml 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1<templates>
2<div t-name="web_example.action" class="oe_web_example oe_web_example_stopped">
3 <h4 class="oe_web_example_timer">00:00:00</h4>
4 <p class="oe_web_example_start">
5 <button type="button">Start</button>
6 </p>
7 <p class="oe_web_example_stop">
8 <button type="button">Stop</button>
9 </p>
10</div>
11</templates>
120
=== added file 'addons/web/doc/module/testing_0.png'
13Binary files addons/web/doc/module/testing_0.png 1970-01-01 00:00:00 +0000 and addons/web/doc/module/testing_0.png 2013-02-18 15:08:21 +0000 differ1Binary files addons/web/doc/module/testing_0.png 1970-01-01 00:00:00 +0000 and addons/web/doc/module/testing_0.png 2013-02-18 15:08:21 +0000 differ
=== added file 'addons/web/doc/module/testing_1.png'
14Binary files addons/web/doc/module/testing_1.png 1970-01-01 00:00:00 +0000 and addons/web/doc/module/testing_1.png 2013-02-18 15:08:21 +0000 differ2Binary files addons/web/doc/module/testing_1.png 1970-01-01 00:00:00 +0000 and addons/web/doc/module/testing_1.png 2013-02-18 15:08:21 +0000 differ
=== removed file 'addons/web/doc/module/web_example.xml'
--- addons/web/doc/module/web_example.xml 2012-12-05 13:28:54 +0000
+++ addons/web/doc/module/web_example.xml 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1<!-- web_example/web_example.xml -->
2<openerp>
3 <data>
4 <record model="ir.actions.client" id="action_client_example">
5 <field name="name">Example Client Action</field>
6 <field name="tag">example.action</field>
7 </record>
8 <menuitem action="action_client_example"
9 id="menu_client_example"/>
10 </data>
11</openerp>
120
=== modified file 'addons/web/doc/testing.rst'
--- addons/web/doc/testing.rst 2012-11-16 11:10:43 +0000
+++ addons/web/doc/testing.rst 2013-02-18 15:08:21 +0000
@@ -327,6 +327,8 @@
327:js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or327:js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or
328``rpc``.328``rpc``.
329329
330.. _testing-rpc-mock:
331
330Mock RPC332Mock RPC
331++++++++333++++++++
332334
333335
=== modified file 'addons/web/doc/widget.rst'
--- addons/web/doc/widget.rst 2012-12-12 16:57:39 +0000
+++ addons/web/doc/widget.rst 2013-02-18 15:08:21 +0000
@@ -93,7 +93,7 @@
93 Any override to :js:func:`~openerp.web.Widget.renderElement` which93 Any override to :js:func:`~openerp.web.Widget.renderElement` which
94 does not call its ``_super`` **must** call94 does not call its ``_super`` **must** call
95 :js:func:`~openerp.web.Widget.setElement` with whatever it95 :js:func:`~openerp.web.Widget.setElement` with whatever it
96 generated or the widget's behavior is undefined.r96 generated or the widget's behavior is undefined.
9797
98 .. note::98 .. note::
9999