diff --git a/Makefile b/Makefile index 0a4d41800e0..9e84e356aaf 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ -.PHONY: all release clean +.PHONY: all doc release clean HOST = 127.0.0.1 PORT = 8080 - all: run run: @@ -24,6 +23,9 @@ clean: @rm -rf dist @rm -rf *.egg-info -cloc: - cloc openerpweb/*.py addons/*/controllers/*.py addons/*/static/src/*.js addons/*/static/src/js/*.js addons/*/static/src/css/*.css addons/*/static/src/xml/*.xml +doc: + make -C doc html + +cloc: + cloc addons/*/common/*.py addons/*/controllers/*.py addons/*/static/src/*.js addons/*/static/src/js/*.js addons/*/static/src/css/*.css addons/*/static/src/xml/*.xml diff --git a/README.web b/README.web index 50cd4fcaaf6..72393bacd34 100644 --- a/README.web +++ b/README.web @@ -1,42 +1,9 @@ -Coding style ------------- - -Javascript - http://javascript.crockford.com/code.html with the following amendements: - - Line Length should be 160 (132?), dont split at 80, rationale in 2011 we all use 16/9 screens - - http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml ? - -Modules Conventions -------------------- - -addons//controllers/ python controller -addons//controllers/main.py main python controller is there is only one (or should it be .py ?) -addons//static/ static directory (directly served by the web server) -addons//static// directory containing an external javascrip library respect the directory structure of upstream is this directory -addons//static/openerp/ module specfic static files -addons//static/openerp/js/ module specific javscript files -addons//static/openerp/css/ module specific css files -addons//static/openerp/img/ module specific images files -addons//static/openerp/ other files -addons//__openerp__.py module manifest referencing js and css files - - -Dependecies +OpenERP Web ----------- -Depends on -install "CherryPy>=3.1.2" "-d cherrypy" -install "simplejson>=2.0.9" "-d simplejson" +To build the documentation use: -Maybe soon on +$ make doc -#install "Babel>=0.9.4" "-d babel" -#install "pytz>=2009j" "-d pytz" +then look at doc/build/html/index.html -Probably not anymore on: - -#install "Mako>=0.2.4" "-d mako" -#install "formencode>=1.2.2" "-d formencode" -#install "pyparsing>=1.5.2" "-f pyparsing.py" -#install "xlwt>=0.7" "-d xlwt" diff --git a/addons/web/common/dispatch.py b/addons/web/common/dispatch.py index 0f2b7fd2293..0829f360806 100644 --- a/addons/web/common/dispatch.py +++ b/addons/web/common/dispatch.py @@ -4,6 +4,7 @@ from __future__ import with_statement import functools import logging import os +import pprint import sys import traceback import uuid @@ -26,6 +27,8 @@ import backendrpc as backend __all__ = ['Root', 'jsonrequest', 'httprequest', 'Controller', 'WebRequest', 'JsonRequest', 'HttpRequest'] +_logger = logging.getLogger(__name__) + #----------------------------------------------------------- # Globals (wont move into a pool) #----------------------------------------------------------- @@ -159,8 +162,8 @@ class JsonRequest(WebRequest): else: self.jsonrequest = simplejson.loads(request, object_hook=nonliterals.non_literal_decoder) self.init(self.jsonrequest.get("params", {})) - if self.debug or 1: - print "--> %s.%s %s" % (controller.__class__.__name__, method.__name__, self.jsonrequest) + if _logger.isEnabledFor(logging.DEBUG): + _logger.debug("--> %s.%s\n%s", controller.__class__.__name__, method.__name__, pprint.pformat(self.jsonrequest)) response['id'] = self.jsonrequest.get('id') response["result"] = method(controller, self, **self.params) except backend.OpenERPUnboundException: @@ -184,7 +187,7 @@ class JsonRequest(WebRequest): } } except Exception: - logging.getLogger('openerp.JSONRequest.dispatch').exception\ + logging.getLogger(__name__ + '.JSONRequest.dispatch').exception\ ("An error occured while handling a json request") error = { 'code': 300, @@ -197,10 +200,8 @@ class JsonRequest(WebRequest): if error: response["error"] = error - if self.debug or 1: - print "<--", response - print - + if _logger.isEnabledFor(logging.DEBUG): + _logger.debug("<--\n%s", pprint.pformat(response)) content = simplejson.dumps(response, cls=nonliterals.NonLiteralEncoder) return werkzeug.wrappers.Response( content, headers=[('Content-Type', 'application/json'), @@ -237,15 +238,13 @@ class HttpRequest(WebRequest): akw[key] = value else: akw[key] = type(value) - if self.debug or 1: - print "%s --> %s.%s %r" % (self.httprequest.method, controller.__class__.__name__, method.__name__, akw) + _logger.debug("%s --> %s.%s %r", self.httprequest.method, controller.__class__.__name__, method.__name__, akw) r = method(controller, self, **self.params) if self.debug or 1: if isinstance(r, werkzeug.wrappers.BaseResponse): - print '<--', r + _logger.debug('<-- %s', r) else: - print "<--", 'size:', len(r) - print + _logger.debug("<-- size: %s", len(r)) return r def make_response(self, data, headers=None, cookies=None): @@ -317,7 +316,7 @@ class Root(object): by the server, will be filtered by this pattern """ def __init__(self, options): - self.root = werkzeug.urls.Href('/web/webclient/home') + self.root = werkzeug.urls.Href('/web/webclient/home?debug') self.config = options self.session_cookie = 'sessionid' @@ -391,7 +390,7 @@ class Root(object): manifest_path = os.path.join(addons_path, module, '__openerp__.py') if os.path.isfile(manifest_path): manifest = ast.literal_eval(open(manifest_path).read()) - print "Loading", module + _logger.info("Loading %s", module) m = __import__(module) addons_module[module] = m addons_manifest[module] = manifest @@ -424,6 +423,6 @@ class Root(object): meth = rest[0] m = getattr(c, meth) if getattr(m, 'exposed', False): - print "Dispatching to", ps, c, meth, m + _logger.debug("Dispatching to %s %s %s", ps, c, meth) return m return None diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 8b61484d794..c79bf4552b1 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -11,6 +11,7 @@ import simplejson import textwrap import xmlrpclib import time +import zlib import webrelease from xml.etree import ElementTree from cStringIO import StringIO @@ -23,8 +24,6 @@ openerpweb.nonliterals = web.common.nonliterals from babel.messages.pofile import read_po -_REPORT_POLLER_DELAY = 0.05 - # Should move to openerpweb.Xml2Json class Xml2Json: # xml2json-direct @@ -104,7 +103,6 @@ home_template = textwrap.dedent(""" %(javascript)s '%i for i in jslist]) # css tags csslist = ['/web/webclient/css'] if req.debug: - csslist = manifest_glob(req.config.addons_path, ['web'], 'css') + csslist = [i + '?debug=' + str(time.time()) for i in manifest_glob(req.config.addons_path, ['web'], 'css')] css = "\n ".join([''%i for i in csslist]) r = home_template % { 'javascript': js, @@ -453,8 +451,6 @@ def load_actions_from_ir_values(req, key, key2, models, meta): def clean_action(req, action): action.setdefault('flags', {}) - if action['type'] != 'ir.actions.act_window': - return action context = req.session.eval_context(req.context) eval_ctx = req.session.evaluation_context(context) @@ -466,7 +462,9 @@ def clean_action(req, action): if isinstance(action.get('domain'), basestring): action['domain'] = eval( action['domain'], eval_ctx ) or [] - return fix_view_modes(action) + if action['type'] == 'ir.actions.act_window': + return fix_view_modes(action) + return action # I think generate_views,fix_view_modes should go into js ActionManager def generate_views(action): @@ -764,6 +762,8 @@ class View(openerpweb.Controller): fvg = Model.fields_view_get(view_id, view_type, context, toolbar, submenu) # todo fme?: check that we should pass the evaluated context here self.process_view(req.session, fvg, context, transform) + if toolbar and transform: + self.process_toolbar(req, fvg['toolbar']) return fvg def process_view(self, session, fvg, context, transform): @@ -795,6 +795,22 @@ class View(openerpweb.Controller): if field.get('context'): field["context"] = self.parse_context(field["context"], session) + def process_toolbar(self, req, toolbar): + """ + The toolbar is a mapping of section_key: [action_descriptor] + + We need to clean all those actions in order to ensure correct + round-tripping + """ + for actions in toolbar.itervalues(): + for action in actions: + if 'context' in action: + action['context'] = self.parse_context( + action['context'], req.session) + if 'domain' in action: + action['domain'] = self.parse_domain( + action['domain'], req.session) + @openerpweb.jsonrequest def add_custom(self, req, view_id, arch): CustomView = req.session.model('ir.ui.view.custom') @@ -884,22 +900,13 @@ class View(openerpweb.Controller): if context_string: elem.set(el, self.parse_context(context_string, session)) -class FormView(View): - _cp_path = "/web/formview" - @openerpweb.jsonrequest - def load(self, req, model, view_id, toolbar=False): - fields_view = self.fields_view_get(req, model, view_id, 'form', toolbar=toolbar) - return {'fields_view': fields_view} + def load(self, req, model, view_id, view_type, toolbar=False): + return self.fields_view_get(req, model, view_id, view_type, toolbar=toolbar) class ListView(View): _cp_path = "/web/listview" - @openerpweb.jsonrequest - def load(self, req, model, view_id, toolbar=False): - fields_view = self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) - return {'fields_view': fields_view} - def process_colors(self, view, row, context): colors = view['arch']['attrs'].get('colors') @@ -918,6 +925,15 @@ class ListView(View): return color[0] return 'maroon' +class TreeView(View): + _cp_path = "/web/treeview" + + @openerpweb.jsonrequest + def action(self, req, model, id): + return load_actions_from_ir_values( + req,'action', 'tree_but_open',[(model, id)], + False) + class SearchView(View): _cp_path = "/web/searchview" @@ -1062,8 +1078,11 @@ class Action(openerpweb.Controller): context = req.session.eval_context(req.context) action_type = Actions.read([action_id], ['type'], context) if action_type: - action = req.session.model(action_type[0]['type']).read([action_id], False, - context) + ctx = {} + if action_type[0]['type'] == 'ir.actions.report.xml': + ctx.update({'bin_size': True}) + ctx.update(context) + action = req.session.model(action_type[0]['type']).read([action_id], False, ctx) if action: value = clean_action(req, action[0]) return {'result': value} @@ -1073,19 +1092,6 @@ class Action(openerpweb.Controller): return clean_action(req, req.session.model('ir.actions.server').run( [action_id], req.session.eval_context(req.context))) -class TreeView(View): - _cp_path = "/web/treeview" - - @openerpweb.jsonrequest - def load(self, req, model, view_id, toolbar=False): - return self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar) - - @openerpweb.jsonrequest - def action(self, req, model, id): - return load_actions_from_ir_values( - req,'action', 'tree_but_open',[(model, id)], - False) - class Export(View): _cp_path = "/web/export" @@ -1336,29 +1342,56 @@ class ExcelExport(Export): fp.close() return data - class Reports(View): _cp_path = "/web/report" + POLLING_DELAY = 0.25 + TYPES_MAPPING = { + 'doc': 'application/vnd.ms-word', + 'html': 'text/html', + 'odt': 'application/vnd.oasis.opendocument.text', + 'pdf': 'application/pdf', + 'sxw': 'application/vnd.sun.xml.writer', + 'xls': 'application/vnd.ms-excel', + } + + @openerpweb.httprequest + def index(self, req, action, token): + action = simplejson.loads(action) - @openerpweb.jsonrequest - def get_report(self, req, action): report_srv = req.session.proxy("report") - context = req.session.eval_context(openerpweb.nonliterals.CompoundContext(req.context, \ - action["context"])) + context = req.session.eval_context( + openerpweb.nonliterals.CompoundContext( + req.context or {}, action[ "context"])) - args = [req.session._db, req.session._uid, req.session._password, action["report_name"], context["active_ids"], {"id": context["active_id"], "model": context["active_model"], "report_type": action["report_type"]}, context] - report_id = report_srv.report(*args) - report = None + report_data = {"id": context["active_id"], "model": context["active_model"]} + if 'report_type' in action: + report_data['report_type'] = action['report_type'] + report_id = report_srv.report( + req.session._db, req.session._uid, req.session._password, + action["report_name"], context["active_ids"], + report_data, context) + + report_struct = None while True: - args2 = [req.session._db, req.session._uid, req.session._password, report_id] - report = report_srv.report_get(*args2) - if report["state"]: + report_struct = report_srv.report_get( + req.session._db, req.session._uid, req.session._password, report_id) + if report_struct["state"]: break - time.sleep(_REPORT_POLLER_DELAY) + time.sleep(self.POLLING_DELAY) + + report = base64.b64decode(report_struct['result']) + if report_struct.get('code') == 'zlib': + report = zlib.decompress(report) + report_mimetype = self.TYPES_MAPPING.get( + report_struct['format'], 'octet-stream') + return req.make_response(report, + headers=[ + ('Content-Disposition', 'attachment; filename="%s.%s"' % (action['report_name'], report_struct['format'])), + ('Content-Type', report_mimetype), + ('Content-Length', len(report))], + cookies={'fileToken': int(token)}) - #TODO: ok now we've got the report, and so what? - return False class Import(View): _cp_path = "/web/import" @@ -1534,4 +1567,4 @@ class Import(View): d+= ('%s: %s' % (str(key),str(val))) msg = 'Error trying to import this record:%s. ErrorMessage:%s %s' % (d,res[2],res[3]) error = {'message':str(msg), 'title':'ImportationError'} - return simplejson.dumps({'error':error}) + return simplejson.dumps({'error':error}) \ No newline at end of file diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index cfb9c9c461d..473e80d1229 100644 --- a/addons/web/static/lib/qweb/qweb2.js +++ b/addons/web/static/lib/qweb/qweb2.js @@ -201,7 +201,7 @@ QWeb2.Engine = (function() { this.templates = {}; this.compiled_templates = {}; this.extend_templates = {}; - this.dict = {}; + this.default_dict = {}; this.tools = QWeb2.tools; this.jQuery = window.jQuery; this.reserved_words = QWeb2.RESERVED_WORDS.slice(0); @@ -323,10 +323,12 @@ QWeb2.Engine = (function() { " return r.join('');"; }, render : function(template, dict) { + var ndict = QWeb2.tools.extend({}, this.default_dict); + QWeb2.tools.extend(ndict, dict); if (this.debug && window['console'] !== undefined) { console.time("QWeb render template " + template); } - var r = this._render(template, dict); + var r = this._render(template, ndict); if (this.debug && window['console'] !== undefined) { console.timeEnd("QWeb render template " + template); } diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index c6241cd4429..3003f9402ac 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -838,7 +838,8 @@ label.error { .openerp label.oe_label_help { cursor: help; } -.openerp .oe_form_field label.oe_label, .openerp .oe_form_field label.oe_label_help { +.openerp label.oe_label, +.openerp label.oe_label_help { text-align: right; margin: 3px 0 0 10px; } diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index b3fc1622ef0..4d19287ed33 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -3,6 +3,7 @@ *---------------------------------------------------------*/ openerp.web.chrome = function(openerp) { +var QWeb = openerp.web.qweb; openerp.web.Notification = openerp.web.Widget.extend({ init: function(parent, element_id) { diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index d826ff34a43..da2afae3680 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -3,6 +3,7 @@ *--------------------------------------------------------*/ openerp.web.core = function(openerp) { +openerp.web.qweb = new QWeb2.Engine(); /** * John Resig Class with factory improvement */ @@ -374,7 +375,7 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web jsonrpc: "2.0", method: "call", params: params, - id:null + id: _.uniqueId('browser-client-') }).then(function () {deferred.resolve.apply(deferred, arguments);}, function(error) {deferred.reject(error, $.Event());}); return deferred.fail(function() { @@ -868,7 +869,7 @@ openerp.web.Widget = openerp.web.SessionAware.extend({ * @param {Object} additional Additional context arguments to pass to the template. */ render: function (additional) { - return QWeb.render(this.template, _.extend({widget: this}, additional || {})); + return openerp.web.qweb.render(this.template, _.extend({widget: this}, additional || {})); }, /** * Method called after rendering. Mostly used to bind actions, perform asynchronous @@ -946,7 +947,7 @@ openerp.web.Widget = openerp.web.SessionAware.extend({ */ openerp.web.OldWidget = openerp.web.Widget.extend({ render: function (additional) { - return QWeb.render(this.template, _.extend(_.extend({}, this), additional || {})); + return openerp.web.qweb.render(this.template, _.extend(_.extend({}, this), additional || {})); } }); diff --git a/addons/web/static/src/js/data_export.js b/addons/web/static/src/js/data_export.js index 15477ffdc41..51ac2cbd568 100644 --- a/addons/web/static/src/js/data_export.js +++ b/addons/web/static/src/js/data_export.js @@ -1,4 +1,5 @@ openerp.web.data_export = function(openerp) { +var QWeb = openerp.web.qweb; openerp.web.DataExport = openerp.web.Dialog.extend({ template: 'ExportTreeView', dialog_title: 'Export Data', diff --git a/addons/web/static/src/js/form.js b/addons/web/static/src/js/form.js index 24331a338e0..4f88edb0a53 100644 --- a/addons/web/static/src/js/form.js +++ b/addons/web/static/src/js/form.js @@ -1,6 +1,7 @@ openerp.web.form = function (openerp) { var _t = openerp.web._t; +var QWeb = openerp.web.qweb; openerp.web.views.add('form', 'openerp.web.FormView'); openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# */{ @@ -46,12 +47,17 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# if (this.embedded_view) { var def = $.Deferred().then(this.on_loaded); var self = this; - setTimeout(function() {def.resolve({fields_view: self.embedded_view});}, 0); + setTimeout(function() {def.resolve(self.embedded_view);}, 0); return def.promise(); } else { var context = new openerp.web.CompoundContext(this.dataset.get_context()); - return this.rpc("/web/formview/load", {"model": this.model, "view_id": this.view_id, - toolbar: this.options.sidebar, context: context}, this.on_loaded); + return this.rpc("/web/view/load", { + "model": this.model, + "view_id": this.view_id, + "view_type": "form", + toolbar: this.options.sidebar, + context: context + }, this.on_loaded); } }, stop: function() { @@ -65,7 +71,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# }, on_loaded: function(data) { var self = this; - this.fields_view = data.fields_view; + this.fields_view = data; var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch); this.$element.html(QWeb.render(this.template, { 'frame': frame, 'view': this })); @@ -94,7 +100,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# this.sidebar.start(); this.sidebar.do_unfold(); this.sidebar.attachments = new openerp.web.form.SidebarAttachments(this.sidebar, this.sidebar.add_section('attachments', "Attachments"), this); - this.sidebar.add_toolbar(data.fields_view.toolbar); + this.sidebar.add_toolbar(this.fields_view.toolbar); this.set_common_sidebar_sections(this.sidebar); } this.has_been_loaded.resolve(); @@ -450,6 +456,34 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView# return id ? [id] : []; } }); +openerp.web.FormDialog = openerp.web.Dialog.extend({ + init: function(parent, options, view_id, dataset) { + this._super(parent, options); + this.dataset = dataset; + this.view_id = view_id; + return this; + }, + start: function() { + this._super(); + this.form = new openerp.web.FormView(this, this.element_id, this.dataset, this.view_id, { + sidebar: false, + pager: false + }); + this.form.start(); + this.form.on_created.add_last(this.on_form_dialog_saved); + this.form.on_saved.add_last(this.on_form_dialog_saved); + return this; + }, + load_id: function(id) { + var self = this; + return this.dataset.read_ids([id], _.keys(this.form.fields_view.fields), function(records) { + self.form.on_record_loaded(records[0]); + }); + }, + on_form_dialog_saved: function() { + this.close(); + } +}); /** @namespace */ openerp.web.form = {}; @@ -1217,11 +1251,16 @@ openerp.web.form.FieldTextXml = openerp.web.form.Field.extend({ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({ init: function(view, node) { + var self = this; this._super(view, node); this.template = "FieldSelection"; - this.field_index = _.map(this.field.selection, function(x, index) { - return {"ikey": "" + index, "ekey": x[0], "label": x[1]}; + this.values = this.field.selection; + _.each(this.values, function(v, i) { + if (v[0] === false && v[1] === '') { + self.values.splice(i, 1); + } }); + this.values.unshift([false, '']); }, start: function() { // Flag indicating whether we're in an event chain containing a change @@ -1251,13 +1290,14 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({ value = value === null ? false : value; value = value instanceof Array ? value[0] : value; this._super(value); - var option = _.detect(this.field_index, function(x) {return x.ekey === value;}); - this.$element.find('select').val(option === undefined ? '' : option.ikey); + var index = 0; + for (var i = 0, ii = this.values.length; i < ii; i++) { + if (this.values[i][0] === value) index = i; + } + this.$element.find('select')[0].selectedIndex = index; }, set_value_from_ui: function() { - var ikey = this.$element.find('select').val(); - var option = _.detect(this.field_index, function(x) {return x.ikey === ikey;}); - this.value = option === undefined ? false : option.ekey; + this.value = this.values[this.$element.find('select')[0].selectedIndex][0]; this._super(); }, update_dom: function() { @@ -1265,9 +1305,8 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({ this.$element.find('select').attr('disabled', this.readonly); }, validate: function() { - var ikey = this.$element.find('select').val(); - var option = _.detect(this.field_index, function(x) {return x.ikey === ikey;}); - this.invalid = this.required && (option === undefined || option.ekey === false); + var value = this.values[this.$element.find('select')[0].selectedIndex]; + this.invalid = !(value && !(this.required && value[0] === false)); }, focus: function() { this.$element.find('select').focus(); diff --git a/addons/web/static/src/js/list-editable.js b/addons/web/static/src/js/list-editable.js index d7a235f5a32..ab78e5e0139 100644 --- a/addons/web/static/src/js/list-editable.js +++ b/addons/web/static/src/js/list-editable.js @@ -74,7 +74,7 @@ openerp.web.list_editable = function (openerp) { }, on_loaded: function (data, grouped) { // tree/@editable takes priority on everything else if present. - this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable; + this.options.editable = data.arch.attrs.editable || this.options.editable; return this._super(data, grouped); } }); @@ -183,7 +183,7 @@ openerp.web.list_editable = function (openerp) { template: 'ListView.row.form', registry: openerp.web.list.form.widgets }); - $.when(self.edition_form.on_loaded({fields_view: self.get_form_fields_view()})).then(function () { + $.when(self.edition_form.on_loaded(self.get_form_fields_view())).then(function () { // put in $.when just in case FormView.on_loaded becomes asynchronous $new_row.find('td') .addClass('oe-field-cell') diff --git a/addons/web/static/src/js/list.js b/addons/web/static/src/js/list.js index 1942bac179a..6029b30f866 100644 --- a/addons/web/static/src/js/list.js +++ b/addons/web/static/src/js/list.js @@ -1,4 +1,5 @@ openerp.web.list = function (openerp) { +var QWeb = openerp.web.qweb; openerp.web.views.add('list', 'openerp.web.ListView'); openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# */ { defaults: { @@ -147,7 +148,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# */ on_loaded: function(data, grouped) { var self = this; - this.fields_view = data.fields_view; + this.fields_view = data; //this.log(this.fields_view); this.name = "" + this.fields_view.arch.attrs.string; @@ -218,7 +219,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# if (!this.sidebar && this.options.sidebar && this.options.sidebar_id) { this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id); this.sidebar.start(); - this.sidebar.add_toolbar(data.fields_view.toolbar); + this.sidebar.add_toolbar(this.fields_view.toolbar); this.set_common_sidebar_sections(this.sidebar); } }, @@ -368,11 +369,12 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView# self.on_loaded(field_view_get, grouped); }; if (this.embedded_view) { - return $.Deferred().then(callback).resolve({fields_view: this.embedded_view}); + return $.Deferred().then(callback).resolve(this.embedded_view); } else { return this.rpc('/web/listview/load', { model: this.model, view_id: this.view_id, + view_type: "tree", context: this.dataset.get_context(context), toolbar: this.options.sidebar }, callback); diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 23fb1ec5215..272e96b7d01 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1,4 +1,5 @@ openerp.web.search = function(openerp) { +var QWeb = openerp.web.qweb; openerp.web.SearchView = openerp.web.Widget.extend({ init: function(parent, element_id, dataset, view_id, defaults) { diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js index 6257dc7e587..a71e4010fcf 100644 --- a/addons/web/static/src/js/view_tree.js +++ b/addons/web/static/src/js/view_tree.js @@ -3,6 +3,7 @@ *---------------------------------------------------------*/ openerp.web.view_tree = function(openerp) { +var QWeb = openerp.web.qweb; openerp.web.views.add('tree', 'openerp.web.TreeView'); /** @@ -31,6 +32,7 @@ openerp.web.TreeView = openerp.web.View.extend({ return this.rpc("/web/treeview/load", { model: this.model, view_id: this.view_id, + view_type: "tree", toolbar: this.view_manager ? !!this.view_manager.sidebar : false }, this.on_loaded); }, diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index f8382cb362b..5e211d0b0cd 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -5,6 +5,7 @@ openerp.web.views = function(openerp) { var _t = openerp.web._t; +var QWeb = openerp.web.qweb; /** * Registry for all the client actions key: tag value: widget @@ -125,11 +126,11 @@ openerp.web.ActionManager = openerp.web.Widget.extend({ (this.client_widget = new ClientWidget(this, action.params)).appendTo(this); }, ir_actions_report_xml: function(action) { - this.rpc('/web/report/get_report', { - action: action, - context: {} - }).then(function(result) { - debugger; + $.blockUI(); + this.session.get_file({ + url: '/web/report', + data: {action: JSON.stringify(action)}, + complete: $.unblockUI }); } }); @@ -443,7 +444,10 @@ openerp.web.Sidebar = openerp.web.Widget.extend({ if (item.action) { var ids = self.widget_parent.get_selected_ids(); if (ids.length == 0) { - //TODO niv: maybe show a warning? + $("
").text(_t("You must choose at least one record.")).dialog({ + title: _t("Warning"), + modal: true + }); return false; } var additional_context = { @@ -453,7 +457,7 @@ openerp.web.Sidebar = openerp.web.Widget.extend({ }; self.rpc("/web/action/load", { action_id: item.action.id, - context: _.extend({"bin_size": true}, additional_context) + context: additional_context }, function(result) { result.result.context = _.extend(result.result.context || {}, additional_context); diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 594bffbb64d..a523b49a863 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -799,10 +799,8 @@ t-att-id="widget.element_id + '_field'" t-att-class="'field_' + widget.type" style="width: 100%"> - - + + @@ -1113,7 +1111,8 @@