From 9262c3c00dfdad634a8f2829abe2d14b6540e63a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Fri, 8 Apr 2011 14:40:20 +0200 Subject: [PATCH 01/34] [FIX] fuckup with deferred for rendering of list (when beyond one section), also only remove old body after new list has rendered otherwise we get an empty list flash even for lists with a bunch of elements bzr revid: xmo@openerp.com-20110408124020-25dprn6gu19y02m6 --- addons/base/static/src/js/list.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 4b1eeaaf993..4fc3ef07720 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -89,7 +89,7 @@ openerp.base.ListView = openerp.base.Controller.extend( var $table = this.$element.find('table'); // remove all data lines - $table.find('tbody').remove(); + var $old_body = $table.find('tbody'); // add new content var columns = this.columns, @@ -102,8 +102,8 @@ openerp.base.ListView = openerp.base.Controller.extend( body = 0, $body = $('').appendTo($table); + var rendered = $.Deferred(); var render_body = function () { - var rendered = $.Deferred(); setTimeout(function () { $body.append( QWeb.render("ListView.rows", { @@ -118,9 +118,12 @@ openerp.base.ListView = openerp.base.Controller.extend( rendered.resolve(); } }, 0); - return rendered.promise(); }; - return render_body(); + render_body(); + + return rendered.promise().then(function () { + $old_body.remove(); + }); }, on_select_row: function (event) { var $target = $(event.currentTarget); From 75bf28388b9c2904576aedc43b61620665ee9cd0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 08:25:41 +0200 Subject: [PATCH 02/34] [IMP] improvements to View.normalize_attrs bzr revid: xmo@openerp.com-20110411062541-mjib0mm8wk7ujlyy --- addons/base/controllers/main.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 96782c1cec4..efc960168c4 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -424,19 +424,16 @@ class View(openerpweb.Controller): :param dict context: evaluation context """ # If @attrs is normalized in json by server, the eval should be replaced by simplejson.loads - attrs = eval(elem.attrib.get('attrs', '{}')) + attrs = openerpweb.ast.literal_eval(elem.get('attrs', '{}')) if 'states' in elem.attrib: - if 'invisible' not in attrs: - attrs['invisible'] = [] - # This should be done by the server - attrs['invisible'].append(('state', 'not in', elem.attrib['states'].split(','))) - del(elem.attrib['states']) + attrs.setdefault('invisible', [])\ + .append(('state', 'not in', elem.attrib.pop('states').split(','))) if attrs: - elem.attrib['attrs'] = simplejson.dumps(attrs) + elem.set('attrs', simplejson.dumps(attrs)) for a in ['invisible', 'readonly', 'required']: if a in elem.attrib: # In the XML we trust - avalue = bool(eval(elem.attrib.get(a, 'False'), + avalue = bool(eval(elem.get(a, 'False'), {'context': context or {}})) if not avalue: del elem.attrib[a] From 5a901eef839cf82dae9886c2e5d7929234e9d86d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 08:27:25 +0200 Subject: [PATCH 03/34] [FIX] dataset tests bzr revid: xmo@openerp.com-20110411062725-7eh31m9vtuasmsjz --- addons/base/test/test_dataset.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/base/test/test_dataset.py b/addons/base/test/test_dataset.py index 80d1e52561b..27d2169bf1b 100644 --- a/addons/base/test/test_dataset.py +++ b/addons/base/test/test_dataset.py @@ -14,13 +14,13 @@ class TestDataSetController(unittest2.TestCase): self.search.return_value = [] self.read.return_value = [] - self.assertFalse(self.dataset.do_find(self.request, 'fake.model')) + self.assertFalse(self.dataset.do_search_read(self.request, 'fake.model')) self.read.assert_called_once_with([], False) def test_regular_find(self): self.search.return_value = [1, 2, 3] - self.dataset.do_find(self.request, 'fake.model') + self.dataset.do_search_read(self.request, 'fake.model') self.read.assert_called_once_with([1, 2, 3], False) def test_ids_shortcut(self): @@ -32,7 +32,7 @@ class TestDataSetController(unittest2.TestCase): ] self.assertEqual( - self.dataset.do_find(self.request, 'fake.model', ['id']), + self.dataset.do_search_read(self.request, 'fake.model', ['id']), [{'id': 1}, {'id': 2}, {'id': 3}]) self.assertFalse(self.read.called) @@ -46,7 +46,7 @@ class TestDataSetController(unittest2.TestCase): result = self.dataset.do_get( self.request, 'fake.model', [3, 2, 1]) self.read.assert_called_once_with( - [3, 2, 1]) + [3, 2, 1], False) self.assertFalse(self.search.called) self.assertEqual( From 669b109bde7786c406b6141f2954677f52668852 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 08:30:54 +0200 Subject: [PATCH 04/34] [FIX] docstring for DataSet.do_search_read: missing 'fields' param bzr revid: xmo@openerp.com-20110411063054-jybr8z734xy3qndp --- addons/base/controllers/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index efc960168c4..c8614c0f5cb 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -363,6 +363,9 @@ class DataSet(openerpweb.Controller): :type model: str :param ids: a list of identifiers :type ids: list + :param fields: a list of fields to fetch, ``False`` or empty to fetch + all fields in the model + :type fields: list | False :returns: a list of records, in the same order as the list of ids :rtype: list """ From f21bb336d3aca07eb135c891dfcaf20818fcebd4 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 09:58:46 +0200 Subject: [PATCH 05/34] [FIX] dataset search, 'context' is popped from kwargs into the request object, and should be taken from there for RPC calls bzr revid: xmo@openerp.com-20110411075846-9qxzabjav0y1l47n --- addons/base/controllers/main.py | 5 ++--- addons/base/test/test_dataset.py | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index c8614c0f5cb..28806083d61 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -334,18 +334,17 @@ class DataSet(openerpweb.Controller): :param int offset: from which index should the results start being returned :param int limit: the maximum number of records to return :param list domain: the search domain for the query - :param dict context: the context in which the search should be executed :param list sort: sorting directives :returns: a list of result records :rtype: list """ Model = request.session.model(model) ids = Model.search(domain or [], offset or 0, limit or False, - sort or False, context or False) + sort or False, request.context) if fields and fields == ['id']: # shortcut read if we only want the ids return map(lambda id: {'id': id}, ids) - return Model.read(ids, fields or False) + return Model.read(ids, fields or False, request.context) @openerpweb.jsonrequest def get(self, request, model, ids, fields=False): diff --git a/addons/base/test/test_dataset.py b/addons/base/test/test_dataset.py index 27d2169bf1b..702c63b0899 100644 --- a/addons/base/test/test_dataset.py +++ b/addons/base/test/test_dataset.py @@ -15,13 +15,14 @@ class TestDataSetController(unittest2.TestCase): self.read.return_value = [] self.assertFalse(self.dataset.do_search_read(self.request, 'fake.model')) - self.read.assert_called_once_with([], False) + self.read.assert_called_once_with([], False, self.request.context) def test_regular_find(self): self.search.return_value = [1, 2, 3] self.dataset.do_search_read(self.request, 'fake.model') - self.read.assert_called_once_with([1, 2, 3], False) + self.read.assert_called_once_with([1, 2, 3], False, + self.request.context) def test_ids_shortcut(self): self.search.return_value = [1, 2, 3] From d99bacbd60615ab9e1a6e18e437d13fc2e949821 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 10:42:59 +0200 Subject: [PATCH 06/34] [TEST] add test for normalize_attrs of states bzr revid: xmo@openerp.com-20110411084259-gpkw2nzpw8ctuhy5 --- addons/base/test/test_view.py | 53 ++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/addons/base/test/test_view.py b/addons/base/test/test_view.py index e5c6162dae0..f20f9e12f61 100644 --- a/addons/base/test/test_view.py +++ b/addons/base/test/test_view.py @@ -2,33 +2,16 @@ import xml.etree.ElementTree import mock import unittest2 +import simplejson import base.controllers.main import openerpweb.nonliterals import openerpweb.openerpweb #noinspection PyCompatibility -class ViewTest(unittest2.TestCase): +class DomainsAndContextsTest(unittest2.TestCase): def setUp(self): self.view = base.controllers.main.View() - def test_identity(self): - base_view = """ -
- - - - - - - """ - - pristine = xml.etree.ElementTree.fromstring(base_view) - transformed = self.view.transform_view(base_view, None) - - self.assertEqual( - xml.etree.ElementTree.tostring(transformed), - xml.etree.ElementTree.tostring(pristine) - ) def test_convert_literal_domain(self): e = xml.etree.ElementTree.Element( @@ -115,3 +98,35 @@ class ViewTest(unittest2.TestCase): openerpweb.nonliterals.Context( session, key=e.get('context').key).get_context_string(), context_string) + +class AttrsNormalizationTest(unittest2.TestCase): + def setUp(self): + self.view = base.controllers.main.View() + + def test_identity(self): + base_view = """ +
+ + + + + + + """ + + pristine = xml.etree.ElementTree.fromstring(base_view) + transformed = self.view.transform_view(base_view, None) + + self.assertEqual( + xml.etree.ElementTree.tostring(transformed), + xml.etree.ElementTree.tostring(pristine) + ) + def test_transform_states(self): + element = xml.etree.ElementTree.Element( + 'field', states="open,closed") + self.view.normalize_attrs(element, {}) + + self.assertIsNone(element.get('states')) + self.assertEqual( + simplejson.loads(element.get('attrs')), + {'invisible': [['state', 'not in', ['open', 'closed']]]}) From 3412b89d95c1febe139e5184ba0295c85bf3a785 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 12:31:18 +0200 Subject: [PATCH 07/34] [IMP] add a bunch of tests for transformation of invisible fields, make View.fields_view_get take a request so it can use the request context for its evaluations bzr revid: xmo@openerp.com-20110411103118-msx5plh2lnz5obps --- addons/base/controllers/main.py | 26 +++++++------ addons/base/test/test_view.py | 48 ++++++++++++++++++++++++ addons/base_calendar/controllers/main.py | 3 +- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 28806083d61..a8dc58625fa 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -403,16 +403,20 @@ class DataSet(openerpweb.Controller): return {'result': r} class View(openerpweb.Controller): - def fields_view_get(self, session, model, view_id, view_type, transform=True, toolbar=False, submenu=False): - Model = session.model(model) - r = Model.fields_view_get(view_id, view_type, {}, toolbar, submenu) + def fields_view_get(self, request, model, view_id, view_type, + transform=True, toolbar=False, submenu=False): + Model = request.session.model(model) + fvg = Model.fields_view_get(view_id, view_type, request.context, + toolbar, submenu) if transform: - context = {} # TODO: dict(ctx_sesssion, **ctx_action) - xml = self.transform_view(r['arch'], session, context) + evaluation_context = request.session.evaluation_context( + request.context or {}) + xml = self.transform_view( + fvg['arch'], request.session, evaluation_context) else: - xml = ElementTree.fromstring(r['arch']) - r['arch'] = Xml2Json.convert_element(xml) - return r + xml = ElementTree.fromstring(fvg['arch']) + fvg['arch'] = Xml2Json.convert_element(xml) + return fvg def normalize_attrs(self, elem, context): """ Normalize @attrs, @invisible, @required, @readonly and @states, so @@ -507,7 +511,7 @@ class FormView(View): @openerpweb.jsonrequest def load(self, req, model, view_id, toolbar=False): - fields_view = self.fields_view_get(req.session, model, view_id, 'form', toolbar=toolbar) + fields_view = self.fields_view_get(req, model, view_id, 'form', toolbar=toolbar) return {'fields_view': fields_view} class ListView(View): @@ -515,7 +519,7 @@ class ListView(View): @openerpweb.jsonrequest def load(self, req, model, view_id, toolbar=False): - fields_view = self.fields_view_get(req.session, model, view_id, 'tree', toolbar=toolbar) + fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) return {'fields_view': fields_view} class SearchView(View): @@ -523,7 +527,7 @@ class SearchView(View): @openerpweb.jsonrequest def load(self, req, model, view_id): - fields_view = self.fields_view_get(req.session, model, view_id, 'search') + fields_view = self.fields_view_get(req, model, view_id, 'search') return {'fields_view': fields_view} class Action(openerpweb.Controller): diff --git a/addons/base/test/test_view.py b/addons/base/test/test_view.py index f20f9e12f61..d8f65ccff99 100644 --- a/addons/base/test/test_view.py +++ b/addons/base/test/test_view.py @@ -1,3 +1,4 @@ +import copy import xml.etree.ElementTree import mock @@ -8,6 +9,11 @@ import base.controllers.main import openerpweb.nonliterals import openerpweb.openerpweb +def field_attrs(fields_view_get, fieldname): + (field,) = filter(lambda f: f['attrs'].get('name') == fieldname, + fields_view_get['arch']['children']) + return field['attrs'] + #noinspection PyCompatibility class DomainsAndContextsTest(unittest2.TestCase): def setUp(self): @@ -130,3 +136,45 @@ class AttrsNormalizationTest(unittest2.TestCase): self.assertEqual( simplejson.loads(element.get('attrs')), {'invisible': [['state', 'not in', ['open', 'closed']]]}) + + def test_transform_invisible(self): + element = xml.etree.ElementTree.Element( + 'field', invisible="context.get('invisible_country', False)") + + empty_context = copy.deepcopy(element) + self.view.normalize_attrs(empty_context, {}) + self.assertEqual(empty_context.get('invisible'), None) + + full_context = copy.deepcopy(element) + self.view.normalize_attrs(full_context, {'invisible_country': True}) + self.assertEqual(full_context.get('invisible'), '1') + + def test_transform_invisible_list_column(self): + req = mock.Mock() + req.context = {'set_editable':True, 'set_visible':True, + 'gtd_visible':True, 'user_invisible':True} + req.session.evaluation_context = \ + openerpweb.openerpweb.OpenERPSession().evaluation_context + req.session.model('project.task').fields_view_get.return_value = { + 'arch': ''' + + + + + + + + + '''} + parsed_view = base.controllers.main.View().fields_view_get( + req, 'project.task', 42, 'tree') + + self.assertTrue(field_attrs(parsed_view, 'sequence')['invisible']) + self.assertTrue(field_attrs(parsed_view, 'user_id')['invisible']) + self.assertTrue( + field_attrs(parsed_view, 'delegated_user_id')['invisible']) + self.assertTrue(field_attrs(parsed_view, 'total_hours')['invisible']) + self.assertTrue( + field_attrs(parsed_view, 'date_deadline')['invisible']) + self.assertTrue(field_attrs(parsed_view, 'type_id')['invisible']) + diff --git a/addons/base_calendar/controllers/main.py b/addons/base_calendar/controllers/main.py index 41081bc7cae..a54d75c5b9b 100644 --- a/addons/base_calendar/controllers/main.py +++ b/addons/base_calendar/controllers/main.py @@ -57,7 +57,7 @@ class CalendarView(View): @openerpweb.jsonrequest def load(self, req, model, view_id): - fields_view = self.fields_view_get(req.session, model, view_id, 'calendar') + fields_view = self.fields_view_get(req, model, view_id, 'calendar') return {'fields_view':fields_view} def convert(self, event): @@ -354,4 +354,3 @@ class CalendarView(View): title = title.strip() description = ', '.join(description).strip() return {'id': event['id'], 'start_date': str(DT.datetime(*starts[:6])), 'end_date': str(DT.datetime(*ends[:6])), 'text': title, 'title': description, 'color': self.colors[event[self.color_field]][-1]} - \ No newline at end of file From 911369822abb9779193137301326e61242b9daa7 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 13:14:51 +0200 Subject: [PATCH 08/34] [ADD] processing of context['set_editable'] on list view bzr revid: xmo@openerp.com-20110411111451-5j6ve9f1wjiuzjfx --- addons/base/controllers/main.py | 49 +++++++++++++++++++++++++++++++ addons/base/static/src/js/list.js | 11 ++++++- addons/base/test/test_view.py | 27 +++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index a8dc58625fa..36e9b0feaee 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import glob, os +import pprint from xml.etree import ElementTree from cStringIO import StringIO @@ -522,6 +523,54 @@ class ListView(View): fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) return {'fields_view': fields_view} + def fields_view_get(self, request, model, view_id, view_type="tree", + transform=True, toolbar=False, submenu=False): + """ Sets @editable on the view's arch if it isn't already set and + ``set_editable`` is present in the request context + """ + view = super(ListView, self).fields_view_get( + request, model, view_id, view_type, transform, toolbar, submenu) + + view_attributes = view['arch']['attrs'] + if request.context.get('set_editable')\ + and 'editable' not in view_attributes: + view_attributes['editable'] = 'bottom' + return view + + @openerpweb.jsonrequest + def fill(self, request, model, id, domain, + offset=0, limit=False): + return self.do_fill(request, model, id, domain, offset, limit) + + def do_fill(self, request, model, id, domain, + offset=0, limit=False): + """ Returns all information needed to fill a table: + + * view with processed ``editable`` flag + * fields (columns) with processed ``invisible`` flag + * rows with processed ``attrs`` and ``colors`` + + .. note:: context is passed through ``request`` parameter + + :param request: OpenERP request + :type request: openerpweb.openerpweb.JsonRequest + :type str model: OpenERP model for this list view + :type int id: view_id, or False if none provided + :param list domain: the search domain to search for + :param int offset: search offset, for pagination + :param int limit: search limit, for pagination + :returns: hell if I have any idea yet + """ + view = self.fields_view_get(request, model, id) + + rows = DataSet().do_search_read(request, model, + offset=offset, limit=limit, + domain=domain) + # rows pipe + # process_attrs + # process_colors + return rows + class SearchView(View): _cp_path = "/base/searchview" diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 4fc3ef07720..247b2d535d9 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -160,7 +160,16 @@ openerp.base.ListView = openerp.base.Controller.extend( // TODO: handle non-empty results.group_by with read_group self.dataset.context = results.context; self.dataset.domain = results.domain; - self.dataset.read_slice(self.dataset.fields, 0, self.limit, self.do_fill_table); + // TODO: need to do 5 billion tons of pre-processing, bypass + // DataSet for now + //self.dataset.read_slice(self.dataset.fields, 0, self.limit, + // self.do_fill_table); + self.rpc('/base/listview/fill', { + 'model': self.dataset.model, + 'id': self.view_id, + 'context': results.context, + 'domain': results.domain + }, self.do_fill_table); }); }, do_update: function () { diff --git a/addons/base/test/test_view.py b/addons/base/test/test_view.py index d8f65ccff99..141bbd5e0db 100644 --- a/addons/base/test/test_view.py +++ b/addons/base/test/test_view.py @@ -178,3 +178,30 @@ class AttrsNormalizationTest(unittest2.TestCase): field_attrs(parsed_view, 'date_deadline')['invisible']) self.assertTrue(field_attrs(parsed_view, 'type_id')['invisible']) +class ListViewTest(unittest2.TestCase): + def setUp(self): + self.view = base.controllers.main.ListView() + self.request = mock.Mock() + self.request.context = {'set_editable': True} + def test_no_editable_editable_context(self): + self.request.session.model('fake').fields_view_get.return_value = \ + {'arch': ''} + view = self.view.fields_view_get(self.request, 'fake', False) + + self.assertEqual(view['arch']['attrs']['editable'], + 'bottom') + def test_editable_top_editable_context(self): + self.request.session.model('fake').fields_view_get.return_value = \ + {'arch': ''} + view = self.view.fields_view_get(self.request, 'fake', False) + + self.assertEqual(view['arch']['attrs']['editable'], + 'top') + + def test_editable_bottom_editable_context(self): + self.request.session.model('fake').fields_view_get.return_value = \ + {'arch': ''} + view = self.view.fields_view_get(self.request, 'fake', False) + + self.assertEqual(view['arch']['attrs']['editable'], + 'bottom') From 5fc7311f1a6bea35701d4aa7c2a68ee1f3ad1a2e Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 11 Apr 2011 14:54:50 +0200 Subject: [PATCH 09/34] [ADD] row-wise colors bzr revid: xmo@openerp.com-20110411125450-3h0ay8fskd1s6nz5 --- addons/base/controllers/main.py | 34 +++++++++++++++++++++++++---- addons/base/static/src/xml/base.xml | 13 +++++++---- addons/base/test/test_view.py | 33 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index 36e9b0feaee..4d75b063a35 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -566,10 +566,36 @@ class ListView(View): rows = DataSet().do_search_read(request, model, offset=offset, limit=limit, domain=domain) - # rows pipe - # process_attrs - # process_colors - return rows + eval_context = request.session.evaluation_context( + request.context) + return [ + {'data': row, + 'attrs': self.process_attrs(view, row, eval_context), + 'color': self.process_colors(view, row, eval_context)} + for row in rows + ] + + def process_attrs(self, view, row, context): + pass + + def process_colors(self, view, row, context): + colors = view['arch']['attrs'].get('colors') + + if not colors: + return None + + color = [ + pair.split(':')[0] + for pair in colors.split(';') + if eval(pair.split(':')[1], dict(context, **row)) + ] + + if not color: + return None + elif len(color) == 1: + return color[0] + return 'maroon' + class SearchView(View): _cp_path = "/base/searchview" diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index caf463cf4e0..8a71b8ebc7a 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -197,9 +197,14 @@ - + + + + + + - + @@ -208,8 +213,8 @@ - - + + - From 8fb463acaee3cc17b50113aa0e1bfa4d4f5fbff6 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 09:23:56 +0200 Subject: [PATCH 15/34] [FIX] don't forget the action's domain when performing a search bzr revid: xmo@openerp.com-20110412072356-gcbuv9ybi6ohx9uz --- addons/base/static/src/js/views.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 1e3851c218f..e70495e3491 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -113,8 +113,9 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ this.searchview.stop(); } this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, search_defaults); - this.searchview.on_search.add(function() { - self.views[self.active_view].controller.do_search.apply(self, arguments); + this.searchview.on_search.add(function(domains, contexts, groupbys) { + self.views[self.active_view].controller.do_search.call( + self, domains.concat(self.domains()), contexts, groupbys); }); return this.searchview.start(); }, @@ -128,6 +129,15 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ on_remove: function() { }, on_edit: function() { + }, + /** + * Domains added on searches by the view manager, to override in subsequent + * view manager in order to add new pieces of domains to searches + * + * @returns an empty list + */ + domains: function () { + return []; } }); @@ -175,6 +185,14 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ this.sidebar.stop(); } this._super(); + }, + /** + * adds action domain to the search domains + * + * @returns the action's domain + */ + domains: function () { + return [this.action.domain]; } }); From ef9880931cb4284258ea2c07f846b6fba0b60794 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 09:27:50 +0200 Subject: [PATCH 16/34] [FIX] add the action's context to the search contexts as well bzr revid: xmo@openerp.com-20110412072750-8338yfl549glz5wz --- addons/base/static/src/js/views.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index e70495e3491..e4deb375a55 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -115,7 +115,8 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ this.searchview = new openerp.base.SearchView(this, this.session, this.element_id + "_search", this.dataset, view_id, search_defaults); this.searchview.on_search.add(function(domains, contexts, groupbys) { self.views[self.active_view].controller.do_search.call( - self, domains.concat(self.domains()), contexts, groupbys); + self, domains.concat(self.domains()), + contexts.concat(self.contexts()), groupbys); }); return this.searchview.start(); }, @@ -138,6 +139,14 @@ openerp.base.ViewManager = openerp.base.Controller.extend({ */ domains: function () { return []; + }, + /** + * Contexts added on searches by the view manager. + * + * @returns an empty list + */ + contexts: function () { + return []; } }); @@ -193,6 +202,14 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ */ domains: function () { return [this.action.domain]; + }, + /** + * adds action context to the search contexts + * + * @returns the action's context + */ + contexts: function () { + return [this.action.context]; } }); From fa02db060dde1e1fd5fbf8dbc8a7c737e2870467 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 09:45:29 +0200 Subject: [PATCH 17/34] [FIX] don't send a domain called 'false' if the action has no domain... bzr revid: xmo@openerp.com-20110412074529-ganfpzhailq2k1zs --- addons/base/static/src/js/views.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index e4deb375a55..74e058c2c79 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -201,6 +201,9 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ * @returns the action's domain */ domains: function () { + if (!this.action.domain) { + return []; + } return [this.action.domain]; }, /** @@ -209,6 +212,9 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ * @returns the action's context */ contexts: function () { + if (!this.action.context) { + return []; + } return [this.action.context]; } }); From 40f26b7327f991fde5071bfc581adf62ba4b08ec Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 09:50:37 +0200 Subject: [PATCH 18/34] [FIX] handling of search views when not provided with an id (still need to go and get a search view, just one with the id 'false' to get the default search view for the model) bzr revid: xmo@openerp.com-20110412075037-6az2uudgp5ktfp8c --- addons/base/static/src/js/views.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/base/static/src/js/views.js b/addons/base/static/src/js/views.js index 74e058c2c79..5e6e3d72745 100644 --- a/addons/base/static/src/js/views.js +++ b/addons/base/static/src/js/views.js @@ -168,8 +168,6 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ this.sidebar.start(); } - // init search view - var view_id = this.action.search_view_id ? this.action.search_view_id[0] || false : false; var search_defaults = {}; _.each(this.action.context, function (value, key) { var match = /^search_default_(.*)$/.exec(key); @@ -177,10 +175,12 @@ openerp.base.ViewManagerAction = openerp.base.ViewManager.extend({ search_defaults[match[1]] = value; } }); - var searchview_loaded = null; - if (view_id) { - searchview_loaded = this.setup_search_view(view_id,search_defaults); - } + + // init search view + var searchview_id = this.action.search_view_id && this.action.search_view_id[0]; + + var searchview_loaded = this.setup_search_view( + searchview_id || false, search_defaults); // schedule auto_search if (searchview_loaded != null && this.action['auto_search']) { From 5d7dae6e6f48b5c29ab9a0e964c4fd2404b431f0 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 10:20:28 +0200 Subject: [PATCH 19/34] [FIX] id fetching for deletion signal in list views bzr revid: xmo@openerp.com-20110412082028-c3yfg1ay14xcrmfh --- addons/base/static/src/js/list.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index e70b442cac0..7827bbad2a2 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -204,7 +204,7 @@ openerp.base.ListView = openerp.base.Controller.extend( // don't link to forms e.stopImmediatePropagation(); this.dataset.unlink( - [this.rows[$(e.currentTarget).closest('tr').prevAll().length].id]); + [this.rows[$(e.currentTarget).closest('tr').prevAll().length].data.id.value]); }, /** * Handles deletion of all selected lines @@ -226,7 +226,7 @@ openerp.base.ListView = openerp.base.Controller.extend( var rows = this.rows; return this.$element.find('th.oe-record-selector input:checked') .closest('tr').map(function () { - return rows[$(this).prevAll().length].id; + return rows[$(this).prevAll().length].data.id.value; }).get(); } }); From e14997c7bcdd34b35e940dbb8123140edf40dd43 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 11:10:36 +0200 Subject: [PATCH 20/34] [FIX] unit tests for list view following change in records topology bzr revid: xmo@openerp.com-20110412091036-w7i9dnh7svqkpa3u --- addons/base/static/test/list.js | 38 +++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/addons/base/static/test/list.js b/addons/base/static/test/list.js index 4a5bb3795fe..c0a34aa71be 100644 --- a/addons/base/static/test/list.js +++ b/addons/base/static/test/list.js @@ -24,7 +24,9 @@ $(document).ready(function () { openerp = window.openerp.init(true); window.openerp.base.chrome(openerp); // views loader stuff + window.openerp.base.data(openerp); window.openerp.base.views(openerp); + window.openerp.base.form(openerp); window.openerp.base.list(openerp); } }); @@ -36,7 +38,11 @@ $(document).ready(function () { listview.on_loaded(fvg); - listview.do_fill_table([{}, {}, {}]).then(function () { + listview.do_fill_table([ + {data: {id: {value: null}}}, + {data: {id: {value: null}}}, + {data: {id: {value: null}}} + ]).then(function () { ok(are(listview.$element.find('tbody th'), '.oe-record-selector')); ok(are(listview.$element.find('tbody th input'), @@ -52,7 +58,11 @@ $(document).ready(function () { listview.on_loaded(fvg); - listview.do_fill_table([{}, {}, {}]).then(function () { + listview.do_fill_table([ + {data: {id: {value: null}}}, + {data: {id: {value: null}}}, + {data: {id: {value: null}}} + ]).then(function () { equal(listview.$element.find('tbody th').length, 0); start(); }); @@ -62,7 +72,11 @@ $(document).ready(function () { {}, null, 'qunit-fixture', {model: null}); listview.on_loaded(fvg); - listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.do_fill_table([ + {data: {id: {value: 1}}}, + {data: {id: {value: 2}}}, + {data: {id: {value: 3}}} + ]).then(function () { listview.$element.find('tbody th input:eq(2)') .attr('checked', true); deepEqual(listview.get_selection(), [3]); @@ -78,7 +92,11 @@ $(document).ready(function () { listview.on_loaded(fvg); - listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.do_fill_table([ + {data: {id: {value: null}}}, + {data: {id: {value: null}}}, + {data: {id: {value: null}}} + ]).then(function () { equal( listview.$element.find('tbody tr td.oe-record-delete button').length, 3); @@ -95,7 +113,11 @@ $(document).ready(function () { listview.on_loaded(fvg); - listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.do_fill_table([ + {data: {id: {value: 1}}}, + {data: {id: {value: 2}}}, + {data: {id: {value: 3}}} + ]).then(function () { listview.$element.find('tbody td.oe-record-delete:eq(2) button').click(); deepEqual(deleted, [3]); listview.$element.find('tbody td.oe-record-delete:eq(0) button').click(); @@ -112,7 +134,11 @@ $(document).ready(function () { listview.on_loaded(fvg); - listview.do_fill_table([{id: 1}, {id: 2}, {id: 3}]).then(function () { + listview.do_fill_table([ + {data: {id: {value: 1}}}, + {data: {id: {value: 2}}}, + {data: {id: {value: 3}}} + ]).then(function () { listview.$element.find('tbody th input:eq(2)') .attr('checked', true); listview.$element.find('tbody th input:eq(1)') From 5ed6be00fbf0aa5ee0afe0a6a61114433696b66b Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 11:22:22 +0200 Subject: [PATCH 21/34] [IMP] basic styling cleanup for listview table bzr revid: xmo@openerp.com-20110412092222-8htdqnzygqa3fsv6 --- addons/base/static/src/css/base.css | 7 +++++++ addons/base/static/src/js/list.js | 4 ++-- addons/base/static/src/xml/base.xml | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 7b686f53fb4..f6d8dac3bee 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -414,6 +414,13 @@ body.openerp { padding-left: 10px; } +/* List */ +.openerp .oe-listview table { + clear: right; + width: 100%; + border-spacing: 0; + border-collapse: collapse; +} /* Form */ .openerp .required.error { diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 7827bbad2a2..bbc69689851 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -35,7 +35,7 @@ openerp.base.ListView = openerp.base.Controller.extend( this.options = _.extend({}, this.defaults, options || {}); }, start: function() { - //this.log('Starting ListView '+this.model+this.view_id) + this.$element.addClass('oe-listview'); return this.rpc("/base/listview/load", {"model": this.model, "view_id":this.view_id, toolbar:!!this.view_manager.sidebar}, this.on_loaded); }, @@ -119,7 +119,7 @@ openerp.base.ListView = openerp.base.Controller.extend( var PAGE_SIZE = 50, bodies_count = Math.ceil(this.rows.length / PAGE_SIZE), body = 0, - $body = $('').appendTo($table); + $body = $('').appendTo($table); var rendered = $.Deferred(); var render_body = function () { diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 7e2c5f9eec7..e0d51d105a7 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -175,7 +175,7 @@ - + - +
From 1755727dd3ecd0758795e3b3b6f4ab9b0b3c115c Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 12:46:59 +0200 Subject: [PATCH 25/34] [FIX] no need for cellspacing bzr revid: xmo@openerp.com-20110412104659-3vp3w2pjq3xfx664 --- addons/base/static/src/xml/base.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 650c26c46eb..97f656378bf 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -170,7 +170,7 @@ - +
From 4e1b38312e6a97522051a4c8548bb480bff480a8 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 13:07:03 +0200 Subject: [PATCH 26/34] [IMP] highlight rows on hover bzr revid: xmo@openerp.com-20110412110703-3chpip0vrcdwg1s3 --- addons/base/static/src/css/base.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index eebf8a54a00..535d152839f 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -425,6 +425,12 @@ body.openerp { .openerp .oe-listview tr.odd { background-color: #f3f3f3; } +.openerp .oe-listview tbody tr:hover { + background-color: #ecebf2; +} +.openerp .oe-listview tbody tr:hover { + background-color: #eae9f0; +} .openerp .oe-listview .oe-field-cell button { padding: 0; From 5c5542e179e5a35bc91720b993e5edb5c973ee46 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 13:17:12 +0200 Subject: [PATCH 27/34] [IMP] merge pager into list table header, remove template call between table and table.header bzr revid: xmo@openerp.com-20110412111712-j3ma06fcec7rhi47 --- addons/base/static/src/css/base.css | 7 +++++ addons/base/static/src/xml/base.xml | 47 ++++++++++++----------------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/addons/base/static/src/css/base.css b/addons/base/static/src/css/base.css index 535d152839f..ee15d02f3f7 100644 --- a/addons/base/static/src/css/base.css +++ b/addons/base/static/src/css/base.css @@ -441,6 +441,13 @@ body.openerp { opacity: 0.5; } +.openerp .oe-listview th.oe-actions { + text-align: left; +} +.openerp .oe-listview th.oe-list-pager { + text-align: right; +} + /** list rounded corners rounded corners are a pain on tables: need to round not only table, but diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 97f656378bf..607260018d4 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -152,38 +152,29 @@
- - -
-
- -
-
- - - - 0 / 0 - - - -
-
- - -
-
- - + + - + - + - +
+ + + + + 1 + / 1 + + + +
@@ -195,7 +186,7 @@
From ce82767d166f9138ac3e98b5683564995c08701d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 14:13:05 +0200 Subject: [PATCH 28/34] [FIX] eval_context and eval_domain should *not* modify the dicts they're given (without cloning them), especially since they're creating circular references (which blow up when they're serialized by simplejson) bzr revid: xmo@openerp.com-20110412121305-mq6l9a4co5xxrfkz --- openerpweb/openerpweb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerpweb/openerpweb.py b/openerpweb/openerpweb.py index 6a4d4146280..8423dc878ab 100644 --- a/openerpweb/openerpweb.py +++ b/openerpweb/openerpweb.py @@ -196,7 +196,7 @@ class OpenERPSession(object): if isinstance(context_to_eval, dict): return context_to_eval - ctx = context or {} + ctx = dict(context or {}) ctx['context'] = ctx # if the domain was unpacked from JSON, it needs the current @@ -252,7 +252,7 @@ class OpenERPSession(object): if isinstance(domain, list): return domain - ctx = context or {} + ctx = dict(context or {}) ctx['context'] = ctx # if the domain was unpacked from JSON, it needs the current From 7bb7044087993d185e06c931cdd8e11f29c7ae3d Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 14:24:02 +0200 Subject: [PATCH 29/34] [IMP] toggle delete button on select/unselect rows bzr revid: xmo@openerp.com-20110412122402-dz53832cx0me8re2 --- addons/base/static/src/js/list.js | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index bbc69689851..4efd7ac84cf 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -73,20 +73,29 @@ openerp.base.ListView = openerp.base.Controller.extend( this.$element.html(QWeb.render("ListView", this)); // Head hook - this.$element.find('#oe-list-delete').click(this.do_delete_selected); + this.$element.find('#oe-list-delete') + .hide() + .click(this.do_delete_selected); + var $table = this.$element.find('table'); // Cell events - this.$element.find('table').delegate( - 'th.oe-record-selector', 'click', function (e) { - // A click in the selection cell should not activate the - // linking feature - e.stopImmediatePropagation(); + $table.delegate( + 'th.oe-record-selector', 'click', function (e) { + // TODO: ~linear performances, would a simple counter work? + if ($table.find('th.oe-record-selector input:checked').length) { + $table.find('#oe-list-delete').show(); + } else { + $table.find('#oe-list-delete').hide(); + } + // A click in the selection cell should not activate the + // linking feature + e.stopImmediatePropagation(); }); - this.$element.find('table').delegate( + $table.delegate( 'td.oe-record-delete button', 'click', this.do_delete); // Global rows handlers - this.$element.find('table').delegate( + $table.delegate( 'tr', 'click', this.on_select_row); // sidebar stuff From 6c9886700e5e413998bc33348dc0e8022aa1752a Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 14:34:07 +0200 Subject: [PATCH 30/34] [ADD] trivial implementation of pager bzr revid: xmo@openerp.com-20110412123407-dl1udbc3vfatb0h6 --- addons/base/static/src/js/list.js | 8 +++++++- addons/base/static/src/xml/base.xml | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 4efd7ac84cf..749f2d18110 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -110,12 +110,18 @@ openerp.base.ListView = openerp.base.Controller.extend( * @returns {Promise} promise to the end of view rendering (list views are asynchronously filled for improved responsiveness) */ do_fill_table: function(records) { + var $table = this.$element.find('table'); this.rows = records; this.dataset.ids = _(records).chain().map(function (record) { return record.data.id.value; }).value(); - var $table = this.$element.find('table'); + // TODO: offset, length, count + var results = this.rows.length; + $table.find('.oe-pager-last').text(results); + $table.find('.oe-pager-total').text(results); + + // remove all data lines var $old_body = $table.find('tbody'); diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 607260018d4..72fe973f1c9 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -167,8 +167,9 @@ - 1 - / 1 + 1 + to 1 + of 1 From b840e25c1d901f0d83c41eef38ada73e8d61bd7b Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 12 Apr 2011 15:02:29 +0200 Subject: [PATCH 31/34] [ADD] basic handling of addition button, not hooked in yet bzr revid: xmo@openerp.com-20110412130229-78sg833pdcbi1gx3 --- addons/base/static/src/js/list.js | 41 ++++++++++++++++++++++++----- addons/base/static/src/xml/base.xml | 15 ++++++++--- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/addons/base/static/src/js/list.js b/addons/base/static/src/js/list.js index 749f2d18110..8d4a1cce360 100644 --- a/addons/base/static/src/js/list.js +++ b/addons/base/static/src/js/list.js @@ -8,7 +8,9 @@ openerp.base.ListView = openerp.base.Controller.extend( // list rows can be deleted 'deletable': true, // whether the column headers should be displayed - 'header': true + 'header': true, + // display addition button, with that label + 'addable': "New" }, /** * @constructs @@ -21,6 +23,7 @@ openerp.base.ListView = openerp.base.Controller.extend( * @param {Boolean} [options.selectable=true] determines whether view rows are selectable (e.g. via a checkbox) * @param {Boolean} [options.header=true] should the list's header be displayed * @param {Boolean} [options.deletable=true] are the list rows deletable + * @param {null|String} [options.addable="New"] should the new-record button be displayed, and what should its label be. Use ``null`` to hide the button. */ init: function(view_manager, session, element_id, dataset, view_id, options) { this._super(session, element_id); @@ -73,6 +76,7 @@ openerp.base.ListView = openerp.base.Controller.extend( this.$element.html(QWeb.render("ListView", this)); // Head hook + this.$element.find('#oe-list-add').click(this.do_add_record); this.$element.find('#oe-list-delete') .hide() .click(this.do_delete_selected); @@ -159,6 +163,23 @@ openerp.base.ListView = openerp.base.Controller.extend( $old_body.remove(); }); }, + /** + * Asks the view manager to switch to a different view, using the provided + * record index (within the current dataset). + * + * If the index is null, ``switch_to_record`` asks for the creation of a + * new record. + * + * @param {Number|null} index the record index (in the current dataset) to switch to + * @param {String} [view="form"] the view to switch to + */ + switch_to_record:function (index, view) { + view = view || 'form'; + this.dataset.index = index; + _.delay(_.bind(function () { + this.view_manager.on_mode_switch(view); + }, this)); + }, on_select_row: function (event) { var $target = $(event.currentTarget); if (!$target.parent().is('tbody')) { @@ -171,12 +192,8 @@ openerp.base.ListView = openerp.base.Controller.extend( if (index == undefined || index === -1) { return; } - this.dataset.index = index; - _.delay(_.bind(function () { - this.view_manager.on_mode_switch('form'); - }, this)); - - }, + this.switch_to_record(index); + }, do_show: function () { // TODO: re-trigger search this.$element.show(); @@ -221,6 +238,16 @@ openerp.base.ListView = openerp.base.Controller.extend( this.dataset.unlink( [this.rows[$(e.currentTarget).closest('tr').prevAll().length].data.id.value]); }, + /** + * Handles signal for the addition of a new record (can be a creation, + * can be the addition from a remote source, ...) + * + * The default implementation is to switch to a new record on the form view + */ + do_add_record: function () { + this.notification['default']('Add', "New record"); + // this.switch_to_record(null); + }, /** * Handles deletion of all selected lines */ diff --git a/addons/base/static/src/xml/base.xml b/addons/base/static/src/xml/base.xml index 72fe973f1c9..7586f62eff7 100644 --- a/addons/base/static/src/xml/base.xml +++ b/addons/base/static/src/xml/base.xml @@ -153,15 +153,22 @@ + + - - -
+ - +