diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index adf61f5facc..a66bd4687a7 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -53,4 +53,7 @@ "static/src/css/data_export.css", "static/src/css/data_import.css", ], + 'qweb' : [ + "static/src/xml/*.xml", + ], } diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 6cc46b476a9..74285b1f444 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -24,19 +24,51 @@ openerpweb = web.common.http # OpenERP Web web Controllers #---------------------------------------------------------- -def concat_files(file_list): - """ Concatenate file content + +def concat_xml(file_list): + """Concatenate xml files return (concat,timestamp) concat: concatenation of file content timestamp: max(os.path.getmtime of file_list) """ + root = None + files_timestamp = 0 + for fname in file_list: + ftime = os.path.getmtime(fname) + if ftime > files_timestamp: + files_timestamp = ftime + + xml = ElementTree.parse(fname).getroot() + + if root is None: + root = ElementTree.Element(xml.tag) + #elif root.tag != xml.tag: + # raise ValueError("Root tags missmatch: %r != %r" % (root.tag, xml.tag)) + + for child in xml.getchildren(): + root.append(child) + return ElementTree.tostring(root, 'utf-8'), files_timestamp + + +def concat_files(file_list, reader=None): + """ Concatenate file content + return (concat,timestamp) + concat: concatenation of file content, read by `reader` + timestamp: max(os.path.getmtime of file_list) + """ + if reader is None: + def reader(f): + with open(f) as fp: + return fp.read() + files_content = [] files_timestamp = 0 for fname in file_list: ftime = os.path.getmtime(fname) if ftime > files_timestamp: files_timestamp = ftime - files_content.append(open(fname).read()) + + files_content.append(reader(fname)) files_concat = "".join(files_content) return files_concat,files_timestamp @@ -98,10 +130,42 @@ class WebClient(openerpweb.Controller): def jslist(self, req, mods=None): return self.manifest_list(req, mods, 'js') + @openerpweb.jsonrequest + def qweblist(self, req, mods=None): + return self.manifest_list(req, mods, 'qweb') + @openerpweb.httprequest def css(self, req, mods=None): - files = [f[0] for f in self.manifest_glob(req, mods, 'css')] - content,timestamp = concat_files(files) + + files = list(self.manifest_glob(req, mods, 'css')) + file_map = dict(files) + + rx_import = re.compile(r"""@import\s+('|")(?!'|"|/|https?://)""", re.U) + rx_url = re.compile(r"""url\s*\(\s*('|"|)(?!'|"|/|https?://)""", re.U) + + + def reader(f): + """read the a css file and absolutify all relative uris""" + with open(f) as fp: + data = fp.read() + + web_path = file_map[f] + web_dir = os.path.dirname(web_path) + + data = re.sub( + rx_import, + r"""@import \1%s/""" % (web_dir,), + data, + ) + + data = re.sub( + rx_url, + r"""url(\1%s/""" % (web_dir,), + data, + ) + return data + + content,timestamp = concat_files((f[0] for f in files), reader) # TODO use timestamp to set Last mofified date and E-tag return req.make_response(content, [('Content-Type', 'text/css')]) @@ -112,6 +176,14 @@ class WebClient(openerpweb.Controller): # TODO use timestamp to set Last mofified date and E-tag return req.make_response(content, [('Content-Type', 'application/javascript')]) + @openerpweb.httprequest + def qweb(self, req, mods=None): + files = [f[0] for f in self.manifest_glob(req, mods, 'qweb')] + content,timestamp = concat_xml(files) + # TODO use timestamp to set Last mofified date and E-tag + return req.make_response(content, [('Content-Type', 'text/xml')]) + + @openerpweb.httprequest def home(self, req, s_action=None, **kw): js = "\n ".join(''%i for i in self.manifest_list(req, None, 'js')) @@ -451,7 +523,7 @@ def clean_action(req, action, do_not_eval=False): # values come from the server, we can just eval them if isinstance(action.get('context'), basestring): action['context'] = eval( action['context'], eval_ctx ) or {} - + if isinstance(action.get('domain'), basestring): action['domain'] = eval( action['domain'], eval_ctx ) or [] else: diff --git a/addons/web/po/ar.po b/addons/web/po/ar.po index 0802e990ae5..0aac2c8aed2 100644 --- a/addons/web/po/ar.po +++ b/addons/web/po/ar.po @@ -8,13 +8,13 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2011-10-07 10:38+0200\n" -"PO-Revision-Date: 2011-11-04 16:13+0000\n" -"Last-Translator: kifcaliph \n" +"PO-Revision-Date: 2011-11-08 05:44+0000\n" +"Last-Translator: Ahmad Khayyat \n" "Language-Team: Arabic \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-05 06:04+0000\n" +"X-Launchpad-Export-Date: 2011-11-08 06:12+0000\n" "X-Generator: Launchpad (build 14231)\n" #: addons/web/static/src/js/view_form.js:355 @@ -210,7 +210,8 @@ msgid "" "Today's enterprise challenges are multiple. We provide one module for each " "need." msgstr "" -"تتعدد تحديات المنشآت اليوم، و لذلك نوفر العديد من وحدات الأكواد لكل إحتياج." +"تتعدد تحديات المنشآت اليوم، و لذلك نوفر العديد من الوحدات البرمجية لكل " +"احتياج." #: addons/web/static/src/xml/base.xml:0 msgid "Open Source" @@ -265,7 +266,7 @@ msgstr "إخفاء هذه الملحوظة" #: addons/web/static/src/xml/base.xml:0 msgid "Disable all tips" -msgstr "تعطيل جميع النصائح" +msgstr "تعطيل جميع الإرشادات" #: addons/web/static/src/xml/base.xml:0 msgid "View#" diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 3430dfe196a..94e36d60419 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1088,7 +1088,7 @@ label.error { list-style: none; } .openerp .oe-view-manager-logs li:before { - content: '→ '; + content: '\2192 '; } .openerp .oe-view-manager-logs a { text-decoration: none; @@ -1448,3 +1448,4 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after { .openerp .oe_view_editor_tree_grid a { display: block; } + diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 22c2b0ba2ea..d85942feead 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -136,10 +136,10 @@ openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# } }); -openerp.web.CrashManager = openerp.web.SessionAware.extend({ - init: function(parent) { - this._super((parent || {}).session); - this.session.on_rpc_error.add(this.on_rpc_error); +openerp.web.CrashManager = openerp.web.CallbackEnabled.extend({ + init: function() { + this._super(); + openerp.connection.on_rpc_error.add(this.on_rpc_error); }, on_rpc_error: function(error) { this.error = error; @@ -959,17 +959,15 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie this._super(null, element_id); openerp.webclient = this; - QWeb.add_template("/web/static/src/xml/base.xml"); var params = {}; if(jQuery.param != undefined && jQuery.deparam(jQuery.param.querystring()).kitten != undefined) { this.$element.addClass("kitten-mode-activated"); } this.$element.html(QWeb.render("Interface", params)); - this.notification = new openerp.web.Notification(); - this.session = new openerp.web.Session(); + this.notification = new openerp.web.Notification(this); this.loading = new openerp.web.Loading(this,"oe_loading"); - this.crashmanager = new openerp.web.CrashManager(this); + this.crashmanager = new openerp.web.CrashManager(); this.header = new openerp.web.Header(this); this.login = new openerp.web.Login(this); diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js index 9563abea49a..7b402cae7fd 100644 --- a/addons/web/static/src/js/core.js +++ b/addons/web/static/src/js/core.js @@ -237,8 +237,8 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry * registry was created. * * An object path is simply a dotted name from the openerp root to the - * object pointed to (e.g. ``"openerp.web.Session"`` for an OpenERP - * session object). + * object pointed to (e.g. ``"openerp.web.Connection"`` for an OpenERP + * connection object). * * @constructs openerp.web.Registry * @param {Object} mapping a mapping of keys to object-paths @@ -338,9 +338,9 @@ openerp.web.CallbackEnabled = openerp.web.Class.extend(/** @lends openerp.web.Ca } }); -openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web.Session# */{ +openerp.web.Connection = openerp.web.CallbackEnabled.extend( /** @lends openerp.web.Connection# */{ /** - * @constructs openerp.web.Session + * @constructs openerp.web.Connection * @extends openerp.web.CallbackEnabled * * @param {String} [server] JSON-RPC endpoint hostname @@ -364,7 +364,9 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web // TODO: session should have an optional name indicating that they'll // be saved to (and revived from) cookies this.name = 'session'; + this.do_load_qweb(['/web/webclient/qweb']); }, + start: function() { this.session_restore(); }, @@ -487,9 +489,11 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web self.user_context = result.context; self.db = result.db; self.session_save(); + self.on_session_valid(); return true; }).then(success_callback); }, + login: function() { this.session_login.apply(this, arguments); }, /** * Reloads uid and session_id from local storage, if they exist */ @@ -577,6 +581,7 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web self.rpc('/web/webclient/jslist', {"mods": modules}, function(files) { self.do_load_js(file_list.concat(files)); }); + self.rpc('/web/webclient/qweblist', {"mods": modules}, self.do_load_qweb); openerp._modules_loaded = true; }); }); @@ -610,6 +615,12 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web this.on_modules_loaded(); } }, + do_load_qweb: function(files) { + var self = this; + _.each(files, function(file) { + openerp.web.qweb.add_template(file); + }); + }, on_modules_loaded: function() { for(var j=0; j\n" "POT-Creation-Date: 2011-10-07 10:39+0200\n" -"PO-Revision-Date: 2011-11-03 15:06+0000\n" -"Last-Translator: kifcaliph \n" +"PO-Revision-Date: 2011-11-08 05:50+0000\n" +"Last-Translator: Ahmad Khayyat \n" "Language-Team: Arabic \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-11-04 05:32+0000\n" +"X-Launchpad-Export-Date: 2011-11-08 06:12+0000\n" "X-Generator: Launchpad (build 14231)\n" #: addons/web_default_home/static/src/xml/web_default_home.xml:0 @@ -23,7 +23,7 @@ msgstr "أهلاً و مرحباً بك في OpenERP" #: addons/web_default_home/static/src/xml/web_default_home.xml:0 msgid "Remember to bookmark this page." -msgstr "لا تنسي إدراج هذه الصفحة ضمن المفضلات" +msgstr "لا تنس إدراج هذه الصفحة ضمن المفضلات" #: addons/web_default_home/static/src/xml/web_default_home.xml:0 msgid "Remember your login:" @@ -31,7 +31,7 @@ msgstr "تذكر كلمة المرور" #: addons/web_default_home/static/src/xml/web_default_home.xml:0 msgid "Choose the first OpenERP Application you want to install.." -msgstr "اختر أول برنامج OpenERP للتثبيت" +msgstr "اختر أول تطبيق OpenERP تود تثبيته" #: addons/web_default_home/static/src/xml/web_default_home.xml:0 msgid "Install" diff --git a/addons/web_diagram/__openerp__.py b/addons/web_diagram/__openerp__.py index 584c0a16e66..cd9eb719934 100644 --- a/addons/web_diagram/__openerp__.py +++ b/addons/web_diagram/__openerp__.py @@ -13,5 +13,8 @@ 'css' : [ "static/src/css/base_diagram.css", ], + 'qweb' : [ + "static/src/xml/*.xml", + ], 'active': True, } diff --git a/addons/web_diagram/static/src/js/diagram.js b/addons/web_diagram/static/src/js/diagram.js index ffa27734769..e4fb3ef5b75 100644 --- a/addons/web_diagram/static/src/js/diagram.js +++ b/addons/web_diagram/static/src/js/diagram.js @@ -4,7 +4,6 @@ openerp.web_diagram = function (openerp) { var QWeb = openerp.web.qweb; -QWeb.add_template('/web_diagram/static/src/xml/base_diagram.xml'); openerp.web.views.add('diagram', 'openerp.web.DiagramView'); openerp.web.DiagramView = openerp.web.View.extend({ searchable: false, diff --git a/addons/web_gantt/__openerp__.py b/addons/web_gantt/__openerp__.py index d2b24f96d08..cd24a8f7314 100644 --- a/addons/web_gantt/__openerp__.py +++ b/addons/web_gantt/__openerp__.py @@ -9,5 +9,8 @@ 'static/src/js/gantt.js' ], "css": ['static/lib/dhtmlxGantt/codebase/dhtmlxgantt.css'], + 'qweb' : [ + "static/src/xml/*.xml", + ], 'active': True } diff --git a/addons/web_gantt/static/src/js/gantt.js b/addons/web_gantt/static/src/js/gantt.js index bdd57b7bf0a..d2eb3aed899 100644 --- a/addons/web_gantt/static/src/js/gantt.js +++ b/addons/web_gantt/static/src/js/gantt.js @@ -3,7 +3,6 @@ *---------------------------------------------------------*/ openerp.web_gantt = function (openerp) { var QWeb = openerp.web.qweb; -QWeb.add_template('/web_gantt/static/src/xml/web_gantt.xml'); openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView'); openerp.web_gantt.GanttView = openerp.web.View.extend({ diff --git a/addons/web_graph/__openerp__.py b/addons/web_graph/__openerp__.py index 68775b7c0e3..d7c37acb180 100644 --- a/addons/web_graph/__openerp__.py +++ b/addons/web_graph/__openerp__.py @@ -7,5 +7,8 @@ "static/lib/dhtmlxGraph/codebase/dhtmlxchart_debug.js", "static/src/js/graph.js"], "css": ["static/lib/dhtmlxGraph/codebase/dhtmlxchart.css"], + 'qweb' : [ + "static/src/xml/*.xml", + ], "active": True } diff --git a/addons/web_graph/static/src/js/graph.js b/addons/web_graph/static/src/js/graph.js index 33321da970a..04e9d77f5d0 100644 --- a/addons/web_graph/static/src/js/graph.js +++ b/addons/web_graph/static/src/js/graph.js @@ -13,7 +13,6 @@ var COLOR_PALETTE = [ '#cc0000', '#d400a8']; var QWeb = openerp.web.qweb; -QWeb.add_template('/web_graph/static/src/xml/web_graph.xml'); openerp.web.views.add('graph', 'openerp.web_graph.GraphView'); openerp.web_graph.GraphView = openerp.web.View.extend({ diff --git a/addons/web_kanban/__openerp__.py b/addons/web_kanban/__openerp__.py index f39cd64999b..92d60b0f4ed 100644 --- a/addons/web_kanban/__openerp__.py +++ b/addons/web_kanban/__openerp__.py @@ -9,5 +9,8 @@ "css": [ "static/src/css/kanban.css" ], + 'qweb' : [ + "static/src/xml/*.xml", + ], 'active': True } diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 6c6ddd57dec..86818f6541c 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -278,12 +278,18 @@ border-color: #D979C1; } -/* Alert color */ -.openerp .oe_kanban_color_alert .oe_kanban_color_border { +/* Red border */ +.openerp .oe_kanban_color_alert .oe_kanban_color_border, +.openerp .oe_kanban_color_red .oe_kanban_color_border { border-color: #c00 !important; } -/* Green color */ +/* Green border */ .openerp .oe_kanban_color_green .oe_kanban_color_border { border-color: #0c0 !important; } + +/* Blue border */ +.openerp .oe_kanban_color_blue .oe_kanban_color_border { + border-color: #00c !important; +} diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 9ba02c48e9a..b2d5dcadc25 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -2,7 +2,6 @@ openerp.web_kanban = function (openerp) { var _t = openerp.web._t; var QWeb = openerp.web.qweb; -QWeb.add_template('/web_kanban/static/src/xml/web_kanban.xml'); openerp.web.views.add('kanban', 'openerp.web_kanban.KanbanView'); openerp.web_kanban.KanbanView = openerp.web.View.extend({ @@ -25,7 +24,7 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({ this.form_dialog.on_form_dialog_saved.add_last(this.do_reload); this.aggregates = {}; this.qweb = new QWeb2.Engine(); - this.qweb.debug = (window.location.search.indexOf('?debug') !== -1); + this.qweb.debug = openerp.connection.debug; this.qweb.default_dict = { '_' : _, '_t' : _t @@ -53,17 +52,8 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({ this.has_been_loaded.resolve(); }, add_qweb_template: function() { - var group_operator = ['avg', 'max', 'min', 'sum', 'count'] for (var i=0, ii=this.fields_view.arch.children.length; i < ii; i++) { var child = this.fields_view.arch.children[i]; - if (child.tag === "field") { - for(j=0, jj=group_operator.length; j < jj; j++) { - if (child.attrs[group_operator[j]]) { - this.aggregates[child.attrs.name] = child.attrs[group_operator[j]]; - break; - } - } - } if (child.tag === "templates") { this.transform_qweb_template(child); this.qweb.add_template(openerp.web.json_node_to_xml(child)); @@ -72,18 +62,25 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({ } }, transform_qweb_template: function(node) { - var qweb_prefix = QWeb.prefix; + var qweb_prefix = QWeb.prefix, + group_operator = ['avg', 'max', 'min', 'sum', 'count']; switch (node.tag) { case 'field': - node.tag = 't'; - node.attrs['t-esc'] = 'record.' + node.attrs['name'] + '.value'; + node.tag = qweb_prefix; + node.attrs[qweb_prefix + '-esc'] = 'record.' + node.attrs['name'] + '.value'; + for (var j = 0, jj = group_operator.length; j < jj; j++) { + if (node.attrs[group_operator[j]]) { + this.aggregates[node.attrs.name] = node.attrs[group_operator[j]]; + break; + } + } break case 'button': case 'a': var type = node.attrs.type || ''; if (_.indexOf('action,object,edit,delete,color'.split(','), type) !== -1) { _.each(node.attrs, function(v, k) { - if (_.indexOf('icon,type,name,string,context,states'.split(','), k) != -1) { + if (_.indexOf('icon,type,name,string,context,states,kanban_states'.split(','), k) != -1) { node.attrs['data-' + k] = v; delete(node.attrs[k]); } @@ -92,7 +89,13 @@ openerp.web_kanban.KanbanView = openerp.web.View.extend({ var states = _.map(node.attrs['data-states'].split(','), function(state) { return "record.state.raw_value == '" + _.trim(state) + "'"; }); - node.attrs['t-if'] = states.join(' or '); + node.attrs[qweb_prefix + '-if'] = states.join(' or '); + } + if (node.attrs['data-kanban_states']) { + var states = _.map(node.attrs['data-kanban_states'].split(','), function(state) { + return "record.kanban_state.raw_value == '" + _.trim(state) + "'"; + }); + node.attrs[qweb_prefix + '-if'] = states.join(' or '); } if (node.attrs['data-string']) { node.attrs.title = node.attrs['data-string'];