diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 6d12f8a49fe..1d5cfabec2c 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -668,7 +668,7 @@ class WebClient(openerpweb.Controller): messages = ir_translation.search_read([('module','in',mods),('lang','=',lang), ('comments','like','openerp-web'),('value','!=',False), ('value','!=','')], - ['module','src','value','lang'], order='module') + ['module','src','value','lang'], order='module') for mod, msg_group in itertools.groupby(messages, key=operator.itemgetter('module')): translations_per_module.setdefault(mod,{'messages':[]}) translations_per_module[mod]['messages'].extend({'id': m['src'], @@ -797,9 +797,9 @@ class Session(openerpweb.Controller): return { "session_id": req.session_id, "uid": req.session._uid, - "context": req.session.get_context() if req.session._uid else {}, + "user_context": req.session.get_context() if req.session._uid else {}, "db": req.session._db, - "login": req.session._login, + "username": req.session._login, } @openerpweb.jsonrequest @@ -1072,7 +1072,7 @@ class DataSet(openerpweb.Controller): @openerpweb.jsonrequest def call(self, req, model, method, args, domain_id=None, context_id=None): return self._call_kw(req, model, method, args, {}) - + @openerpweb.jsonrequest def call_kw(self, req, model, method, args, kwargs): return self._call_kw(req, model, method, args, kwargs) @@ -1186,7 +1186,7 @@ class Binary(openerpweb.Controller): if width > 500: width = 500 if height > 500: height = 500 image_base64 = openerp.tools.image_resize_image(base64_source=image_base64, size=(width, height), encoding='base64', filetype='PNG') - + image_data = base64.b64decode(image_base64) except (TypeError, xmlrpclib.Fault): @@ -1468,7 +1468,7 @@ class Export(View): fields = self.fields_get(req, model) if ".id" in export_fields: fields['.id'] = fields.pop('id', {'string': 'ID'}) - + # To make fields retrieval more efficient, fetch all sub-fields of a # given field at the same time. Because the order in the export list is # arbitrary, this requires ordering all sub-fields of a given field diff --git a/addons/web/session.py b/addons/web/session.py index 54ccac79578..30e9308d4e1 100644 --- a/addons/web/session.py +++ b/addons/web/session.py @@ -18,11 +18,14 @@ _logger = logging.getLogger(__name__) class AuthenticationError(Exception): pass +class SessionExpiredException(Exception): + pass + class Service(object): def __init__(self, session, service_name): self.session = session self.service_name = service_name - + def __getattr__(self, method): def proxy_method(*args): result = self.session.send(self.service_name, method, *args) @@ -60,7 +63,7 @@ class OpenERPSession(object): in a web session. .. attribute:: context - + The session context, a ``dict``. Can be reloaded by calling :meth:`openerpweb.openerpweb.OpenERPSession.get_context` @@ -80,7 +83,7 @@ class OpenERPSession(object): self._suicide = False self.context = {} self.jsonp_requests = {} # FIXME use a LRU - + def send(self, service_name, method, *args): code_string = "warning -- %s\n\n%s" try: @@ -112,7 +115,7 @@ class OpenERPSession(object): def authenticate(self, db, login, password, env=None): uid = self.proxy('common').authenticate(db, login, password, env) self.bind(db, uid, login, password) - + if uid: self.get_context() return uid @@ -152,6 +155,8 @@ class OpenERPSession(object): :type model: str :rtype: a model object """ + if self._db == False: + raise SessionExpiredException("Session expired") return Model(self, model) diff --git a/addons/web/static/lib/cleditor/jquery.cleditor.js b/addons/web/static/lib/cleditor/jquery.cleditor.js index 0fff0152776..e3446991daf 100644 --- a/addons/web/static/lib/cleditor/jquery.cleditor.js +++ b/addons/web/static/lib/cleditor/jquery.cleditor.js @@ -52,7 +52,7 @@ docCSSFile: // CSS file used to style the document contained within the editor "", bodyStyle: // style to assign to document body contained within the editor - "margin:4px; font:10pt Arial,Verdana; cursor:text" + "margin:4px; color:#4c4c4c; font-size:13px; font-family:\"Lucida Grande\",Helvetica,Verdana,Arial,sans-serif; cursor:text" }, // Define all usable toolbar buttons - the init string property is @@ -894,7 +894,7 @@ var $toolbar = editor.$toolbar, $group = $toolbar.children("div:last"), - wid = $main.width(); + wid = /%/.test("" + options.width) ? options.width : $main.width(); // Resize the toolbar var hgt = $group.offset().top + $group.outerHeight() - $toolbar.offset().top + 1; diff --git a/addons/web/static/lib/py.js/lib/py.js b/addons/web/static/lib/py.js/lib/py.js index 4ef92b40112..8d6443b7753 100644 --- a/addons/web/static/lib/py.js/lib/py.js +++ b/addons/web/static/lib/py.js/lib/py.js @@ -521,7 +521,7 @@ var py = {}; } }; py.PY_getAttr = function (o, attr_name) { - return PY_ensurepy(o.__getattribute__(attr_name)); + return PY_ensurepy(o.__getattribute__(attr_name),attr_name); }; py.PY_str = function (o) { var v = o.__str__(); @@ -998,7 +998,7 @@ var py = {}; } var t = py.PY_call(py.tuple); for(var i=0; i li:hover { - background-color: #f0f0fa; + background-color: #efeff8; background-image: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6)); background-image: -webkit-linear-gradient(top, #f0f0fa, #eeeef6); background-image: -moz-linear-gradient(top, #f0f0fa, #eeeef6); @@ -748,7 +748,7 @@ width: 200px; } .openerp .oe_sidebar .oe_dropdown_menu .oe_sidebar_add_attachment:hover { - background-color: #f0f0fa; + background-color: #efeff8; background-image: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6)); background-image: -webkit-linear-gradient(top, #f0f0fa, #eeeef6); background-image: -moz-linear-gradient(top, #f0f0fa, #eeeef6); @@ -846,7 +846,7 @@ border: 1px solid #222222; color: white; margin: 0; - background-color: #b92020; + background-color: #8c1313; background-image: -webkit-gradient(linear, left top, left bottom, from(#b92020), to(#600606)); background-image: -webkit-linear-gradient(top, #b92020, #600606); background-image: -moz-linear-gradient(top, #b92020, #600606); @@ -903,7 +903,7 @@ right: 0; bottom: 0; text-shadow: 0 1px 1px #999999; - background-color: #b41616; + background-color: #8a0e0e; background-image: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606)); background-image: -webkit-linear-gradient(top, #b41616, #600606); background-image: -moz-linear-gradient(top, #b41616, #600606); @@ -1000,7 +1000,7 @@ width: 100%; height: 32px; background-color: #414141; - background-color: #646060; + background-color: #454343; background-image: -webkit-gradient(linear, left top, left bottom, from(#646060), to(#262626)); background-image: -webkit-linear-gradient(top, #646060, #262626); background-image: -moz-linear-gradient(top, #646060, #262626); @@ -1011,7 +1011,7 @@ .openerp .oe_topbar .oe_topbar_anonymous_login { background-color: #dc5f59; color: #eeeeee; - background-color: #fc8787; + background-color: #be4343; background-image: -webkit-gradient(linear, left top, left bottom, from(#fc8787), to(maroon)); background-image: -webkit-linear-gradient(top, #fc8787, maroon); background-image: -moz-linear-gradient(top, #fc8787, maroon); @@ -1101,7 +1101,7 @@ color: #eeeeee; } .openerp .oe_topbar .oe_dropdown_menu li:hover { - background-color: #292929; + background-color: #212121; background-image: -webkit-gradient(linear, left top, left bottom, from(#292929), to(#191919)); background-image: -webkit-linear-gradient(top, #292929, #191919); background-image: -moz-linear-gradient(top, #292929, #191919); @@ -1242,7 +1242,7 @@ .openerp .oe_secondary_submenu { padding: 2px 0 8px 0; margin: 0; - width: 100%; + width: 220px; display: inline-block; } .openerp .oe_secondary_submenu li { @@ -1265,7 +1265,7 @@ color: white; padding: 2px 4px; margin: 1px 6px 0 0; - border: 1px solid lightGray; + border: 1px solid lightgrey; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-border-radius: 4px; -webkit-border-radius: 4px; @@ -1274,6 +1274,13 @@ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); } +.openerp .oe_secondary_submenu .oe_menu_text { + white-space: nowrap; + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + max-width: 85%; +} .openerp .oe_secondary_submenu .oe_menu_counter { float: right; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); @@ -1290,7 +1297,7 @@ transform: scale(1.1); } .openerp .oe_secondary_submenu .oe_active { - border-top: 1px solid lightGray; + border-top: 1px solid lightgrey; border-bottom: 1px solid #dedede; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2); @@ -1340,6 +1347,12 @@ border-right: 4px solid transparent; border-top: 4px solid #4c4c4c; } +.openerp .oe_secondary_submenu .oe_secondary_submenu { + margin-left: -20px; +} +.openerp .oe_secondary_submenu .oe_secondary_submenu li { + margin-left: 20px; +} .openerp .oe_about { background-color: white; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=); @@ -1366,7 +1379,7 @@ right: 0; bottom: 0; text-shadow: 0 1px 1px #999999; - background-color: #b41616; + background-color: #8a0e0e; background-image: -webkit-gradient(linear, left top, left bottom, from(#b41616), to(#600606)); background-image: -webkit-linear-gradient(top, #b41616, #600606); background-image: -moz-linear-gradient(top, #b41616, #600606); @@ -1583,7 +1596,7 @@ } .openerp .oe_view_manager_current > .oe_view_manager_header { border-bottom: 1px solid #cacaca; - background-color: #fcfcfc; + background-color: #ededed; background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede)); background-image: -webkit-linear-gradient(top, #fcfcfc, #dedede); background-image: -moz-linear-gradient(top, #fcfcfc, #dedede); @@ -2044,7 +2057,7 @@ background: none; } .openerp .oe_view_manager_current .oe_form_editable button.oe_highlight { - background-color: #efefef; + background-color: #e3e3e3; background-image: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)); background-image: -webkit-linear-gradient(top, #efefef, #d8d8d8); background-image: -moz-linear-gradient(top, #efefef, #d8d8d8); @@ -2056,7 +2069,7 @@ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset; } .openerp .oe_view_manager_current .oe_form_editable button.oe_highlight:active { - background-color: #e3e3e3; + background-color: #ececec; background-image: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#f6f6f6)); background-image: -webkit-linear-gradient(top, #e3e3e3, #f6f6f6); background-image: -moz-linear-gradient(top, #e3e3e3, #f6f6f6); @@ -2068,7 +2081,7 @@ box-shadow: none; } .openerp .oe_view_manager_current .oe_form_editable button.oe_highlight:hover { - background-color: #f6f6f6; + background-color: #ececec; background-image: -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e3e3e3)); background-image: -webkit-linear-gradient(top, #f6f6f6, #e3e3e3); background-image: -moz-linear-gradient(top, #f6f6f6, #e3e3e3); @@ -2137,7 +2150,7 @@ position: relative; border-bottom: 1px solid #cacaca; padding-left: 2px; - background-color: #fcfcfc; + background-color: #ededed; background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede)); background-image: -webkit-linear-gradient(top, #fcfcfc, #dedede); background-image: -moz-linear-gradient(top, #fcfcfc, #dedede); @@ -2240,7 +2253,7 @@ } .openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span { font-size: 80%; - color: darkGreen; + color: darkgreen; vertical-align: top; position: relative; top: -4px; @@ -2572,7 +2585,7 @@ list-style-type: none; margin: 0 -18px 0 0; padding: 0; - background-color: #fcfcfc; + background-color: #ededed; background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede)); background-image: -webkit-linear-gradient(top, #fcfcfc, #dedede); background-image: -moz-linear-gradient(top, #fcfcfc, #dedede); @@ -2632,7 +2645,7 @@ transform: rotate(45deg); } .openerp ul.oe_form_status li.oe_active, .openerp ul.oe_form_status_clickable li.oe_active { - background-color: #729fcf; + background-color: #5382b9; background-image: -webkit-gradient(linear, left top, left bottom, from(#729fcf), to(#3465a4)); background-image: -webkit-linear-gradient(top, #729fcf, #3465a4); background-image: -moz-linear-gradient(top, #729fcf, #3465a4); @@ -2655,7 +2668,7 @@ cursor: pointer; } .openerp ul.oe_form_status_clickable li:hover { - background-color: #e8e8e8; + background-color: #d9d9d9; background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#cacaca)); background-image: -webkit-linear-gradient(top, #e8e8e8, #cacaca); background-image: -moz-linear-gradient(top, #e8e8e8, #cacaca); @@ -2667,7 +2680,7 @@ text-shadow: 0 -1px 1px #fcfcfc, 0 1px 1px #dedede; } .openerp ul.oe_form_status_clickable li:hover .arrow span { - background-color: #e8e8e8; + background-color: #d9d9d9; background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#cacaca)); background-image: -webkit-linear-gradient(top, #e8e8e8, #cacaca); background-image: -moz-linear-gradient(top, #e8e8e8, #cacaca); @@ -2679,7 +2692,7 @@ color: #7c7bad; } .openerp ul.oe_form_status_clickable li.oe_active:hover { - background-color: #4c85c2; + background-color: #3a699f; background-image: -webkit-gradient(linear, left top, left bottom, from(#4c85c2), to(#284d7d)); background-image: -webkit-linear-gradient(top, #4c85c2, #284d7d); background-image: -moz-linear-gradient(top, #4c85c2, #284d7d); @@ -2835,7 +2848,7 @@ padding: 1px 6px 3px; } .openerp .oe_list .oe_list_content .oe_group_header { - background-color: #fcfcfc; + background-color: #ededed; background-image: -webkit-gradient(linear, left top, left bottom, from(#fcfcfc), to(#dedede)); background-image: -webkit-linear-gradient(top, #fcfcfc, #dedede); background-image: -moz-linear-gradient(top, #fcfcfc, #dedede); @@ -2872,8 +2885,8 @@ position: relative; } .openerp .oe_list_content th.oe_sortable div:after { - position: absolute; - right: 6px; + float: right; + margin-right: 6px; content: ""; margin-top: 7px; border-width: 0 4px 4px; @@ -2932,7 +2945,7 @@ } .openerp .oe_list_content > tbody > tr:nth-child(odd) { background-color: #f0f0fa; - background-color: #f0f0fa; + background-color: #efeff8; background-image: -webkit-gradient(linear, left top, left bottom, from(#f0f0fa), to(#eeeef6)); background-image: -webkit-linear-gradient(top, #f0f0fa, #eeeef6); background-image: -moz-linear-gradient(top, #f0f0fa, #eeeef6); @@ -3134,6 +3147,9 @@ div.ui-widget-overlay { .openerp_ie .oe_form_field_boolean input { background: white; } +.openerp_ie .db_option_table .oe_form_field_selection { + width: auto; +} .openerp_ie input[type='checkbox'] { border: none; background: none; @@ -3208,6 +3224,9 @@ div.ui-widget-overlay { .openerp_ie .oe_topbar { filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#646060', endColorstr='#262626'); } +.openerp_ie .ui-state-error, .openerp_ie .ui-widget-content .ui-state-error, .openerp_ie .ui-widget-header .ui-state-error { + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} .openerp_ie .oe_popup_form { width: 99% !important; } @@ -3291,7 +3310,6 @@ div.ui-widget-overlay { overflow: hidden !important; } } - .blockUI.blockOverlay { background-color: black; opacity: 0.6; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 3aeba573041..42ade77ccbb 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -42,7 +42,7 @@ $sheet-padding: 16px @include box-shadow(none) @mixin vertical-gradient($startColor: #555, $endColor: #333) - background-color: $startColor + background-color: mix($startColor, $endColor) background-image: -webkit-gradient(linear, left top, left bottom, from($startColor), to($endColor)) /* Saf4+, Chrome */ background-image: -webkit-linear-gradient(top, $startColor, $endColor) /* Chrome 10+, Saf5.1+, iOS 5+ */ background-image: -moz-linear-gradient(top, $startColor, $endColor) /* FF3.6 */ @@ -1009,7 +1009,7 @@ $sheet-padding: 16px .oe_secondary_submenu padding: 2px 0 8px 0 margin: 0 - width: 100% + width: 220px display: inline-block li position: relative @@ -1033,6 +1033,12 @@ $sheet-padding: 16px text-shadow: 0 1px 1px rgba(0,0,0,0.2) @include radius(4px) @include box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.2)) + .oe_menu_text + white-space: nowrap + overflow: hidden + display: inline-block + text-overflow: ellipsis + max-width: 85% .oe_menu_counter float: right text-shadow: 0 1px 1px rgba(0,0,0,0.2) @@ -1080,6 +1086,10 @@ $sheet-padding: 16px border-left: 4px solid transparent border-right: 4px solid transparent border-top: 4px solid #4c4c4c + .oe_secondary_submenu + margin-left: -20px + .oe_secondary_submenu li + margin-left: 20px // }}} // About openerp {{{ @@ -2271,8 +2281,8 @@ $sheet-padding: 16px th.oe_sortable div position: relative th.oe_sortable div:after - position: absolute - right: 6px + float: right + margin-right: 6px content: "" margin-top: 7px border-width: 0 4px 4px @@ -2474,6 +2484,8 @@ div.ui-widget-overlay .openerp_ie .oe_form_field_boolean input background: #fff + .db_option_table .oe_form_field_selection + width: auto input[type='checkbox'] border: none background: none @@ -2535,6 +2547,8 @@ div.ui-widget-overlay line-height: 1.7em .oe_topbar filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#646060', endColorstr='#262626') + .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false) .oe_popup_form width: 99% !important .oe_form_label diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index a3b554b7546..1c3723d3e4e 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -42,6 +42,16 @@ instance.web.Notification = instance.web.Widget.extend({ } }); +instance.web.action_notify = function(element, action) { + element.do_notify(action.params.title, action.params.text, action.params.sticky); +}; +instance.web.client_actions.add("action_notify", "instance.web.action_notify"); + +instance.web.action_warn = function(element, action) { + element.do_warn(action.params.title, action.params.text, action.params.sticky); +}; +instance.web.client_actions.add("action_warn", "instance.web.action_warn"); + /** * The very minimal function everything should call to create a dialog * in OpenERP Web Client. @@ -237,6 +247,11 @@ instance.web.CrashManager = instance.web.Class.extend({ if (!this.active) { return; } + // yes, exception handling is shitty + if (error.code === 300 && error.data && error.data.type == "client_exception" && error.data.debug.match("SessionExpiredException")) { + this.show_warning({type: "Session Expired", data: { fault_code: "Your OpenERP session expired. Please refresh the current web page." }}); + return; + } if (error.data.fault_code) { var split = ("" + error.data.fault_code).split('\n')[0].split(' -- '); if (split.length > 1) { @@ -607,6 +622,9 @@ instance.web.Login = instance.web.Widget.extend({ if ($.deparam.querystring().db) { self.params.db = $.deparam.querystring().db; } + if ($.param.fragment().token) { + self.params.token = $.param.fragment().token; + } // used by dbmanager.do_create via internal client action if (self.params.db && self.params.login && self.params.password) { d = self.do_login(self.params.db, self.params.login, self.params.password); @@ -1020,13 +1038,8 @@ instance.web.UserMenu = instance.web.Widget.extend({ if(res.company_id[0] > 1) topbar_name = _.str.sprintf("%s (%s)", topbar_name, res.company_id[1]); self.$el.find('.oe_topbar_name').text(topbar_name); - if(!instance.session.debug) { - self.rpc("/web/database/get_list", {}).done( function(result) { - if (result.length > 1) { - topbar_name = _.str.sprintf("%s (%s)", topbar_name, instance.session.db); - } - self.$el.find('.oe_topbar_name').text(topbar_name); - }); + if (!instance.session.debug) { + topbar_name = _.str.sprintf("%s (%s)", topbar_name, instance.session.db); } var avatar_src = self.session.url('/web/binary/image', {model:'res.users', field: 'image_small', id: self.session.uid}); $avatar.attr('src', avatar_src); diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js index f7a84e608c6..5bbd5316521 100644 --- a/addons/web/static/src/js/corelib.js +++ b/addons/web/static/src/js/corelib.js @@ -1,16 +1,16 @@ /* * Copyright (c) 2012, OpenERP S.A. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + * modification, are permitted provided that the following conditions are met: + * * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. + * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * + * and/or other materials provided with the distribution. + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -243,7 +243,7 @@ instance.web.ParentedMixin = { /** * Backbone's events. Do not ever use it directly, use EventDispatcherMixin instead. - * + * * This class just handle the dispatching of events, it is not meant to be extended, * nor used directly. All integration with parenting and automatic unregistration of * events is done in EventDispatcherMixin. @@ -303,7 +303,7 @@ var Events = instance.web.Class.extend({ }); return lst; }, - + trigger : function(events) { var event, node, calls, tail, args, all, rest; if (!(calls = this._callbacks)) @@ -1043,7 +1043,7 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, { id: payload.id, sid: this.httpsessionid, }; - + var set_sid = function (response, textStatus, jqXHR) { // If response give us the http session id, we store it for next requests... if (response.httpsessionid) { @@ -1054,7 +1054,7 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, { url.url = this.url(url.url, null); var ajax = _.extend({ type: "GET", - dataType: 'jsonp', + dataType: 'jsonp', jsonp: 'jsonp', cache: false, data: data diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index a8b0510389b..43d292b66db 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -49,7 +49,6 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess _(this.module_list).each(function (mod) { self.module_loaded[mod] = true; }); - this.context = {}; this.active_id = null; return this.session_init(); }, @@ -67,7 +66,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess return deferred.then(function() { return self.load_modules(); }); } return $.when( - deferred, + deferred, self.rpc('/web/webclient/bootstrap_translations', {mods: instance._modules}).then(function(trans) { instance.web._t.database.set_bundle(trans); }) @@ -86,13 +85,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess // If immediately follows a login (triggered by trying to restore // an invalid session or no session at all), refresh session data // (should not change, but just in case...) - _.extend(self, { - session_id: result.session_id, - db: result.db, - username: result.login, - uid: result.uid, - user_context: result.context - }); + _.extend(self, result); }); }, session_is_valid: function() { @@ -109,14 +102,7 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess if (!result.uid) { return $.Deferred().reject(); } - - _.extend(self, { - session_id: result.session_id, - db: result.db, - username: result.login, - uid: result.uid, - user_context: result.context - }); + _.extend(self, result); if (!_volatile) { self.set_cookie('session_id', self.session_id); } diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 34ab101fea7..50e768bac59 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -305,9 +305,15 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea * @param dataset * @param view_id * @param defaults - * @param hidden + * @param {Object} [options] + * @param {Boolean} [options.hidden=false] hide the search view + * @param {Boolean} [options.disable_custom_filters=false] do not load custom filters from ir.filters */ - init: function(parent, dataset, view_id, defaults, hidden) { + init: function(parent, dataset, view_id, defaults, options) { + this.options = _.defaults(options || {}, { + hidden: false, + disable_custom_filters: false, + }); this._super(parent); this.dataset = dataset; this.model = dataset.model; @@ -319,8 +325,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea this.inputs = []; this.controls = {}; - this.hidden = !!hidden; - this.headless = this.hidden && !this.has_defaults; + this.headless = this.options.hidden && !this.has_defaults; this.input_subviews = []; @@ -335,7 +340,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea .on('add change reset remove', this.proxy('do_search')) .on('add change reset remove', this.proxy('renderFacets')); - if (this.hidden) { + if (this.options.hidden) { this.$el.hide(); } if (this.headless) { @@ -650,7 +655,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea // CustomFilters will be ready (and CustomFilters#filters will be // correctly filled) by the time this method executes. var custom_filters = this.custom_filters.filters; - if (!_(custom_filters).isEmpty()) { + if (!this.options.disable_custom_filters && !_(custom_filters).isEmpty()) { // Check for any is_default custom filter var personal_filter = _(custom_filters).find(function (filter) { return filter.user_id && filter.is_default; diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index e35a01f5ab0..01d4bf6dd33 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -842,11 +842,10 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM save_deferral = self.dataset.create(values).then(function(r) { return self.record_created(r, prepend_on_create); }, null); - } else if (_.isEmpty(values) && ! self.force_dirty) { + } else if (_.isEmpty(values)) { // Not dirty, noop save save_deferral = $.Deferred().resolve({}).promise(); } else { - self.force_dirty = false; // Write save save_deferral = self.dataset.write(self.datarecord.id, values, {}).then(function(r) { return self.record_saved(r); @@ -1935,7 +1934,6 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ } }; if (!this.node.attrs.special) { - this.view.force_dirty = true; return this.view.recursive_save().then(exec_action); } else { return exec_action(); @@ -2632,7 +2630,7 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc "| removeformat | bullets numbering | outdent " + "indent | link unlink | source", bodyStyle: // style to assign to document body contained within the editor - "margin:4px; font:12px monospace; cursor:text; color:#1F1F1F" + "margin:4px; color:#4c4c4c; font-size:13px; font-family:\"Lucida Grande\",Helvetica,Verdana,Arial,sans-serif; cursor:text" }); this.$cleditor = this.$textarea.cleditor()[0]; this.$cleditor.change(function() { @@ -4946,7 +4944,7 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ } this.$el.find('input').eq(0).val(show_value); } else { - this.$el.find('a').show(!!this.get('value')); + this.$el.find('a').toggle(!!this.get('value')); if (this.get('value')) { var show_value = _t("Download") if (this.view) diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 645338f62c9..fbbfabcacca 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -348,12 +348,27 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi this.sidebar.add_toolbar(this.fields_view.toolbar); this.sidebar.$el.hide(); } + //Sort + if(this.dataset._sort.length){ + if(this.dataset._sort[0].indexOf('-') == -1){ + this.$el.find('th[data-id=' + this.dataset._sort[0] + ']').addClass("sortdown"); + }else { + this.$el.find('th[data-id=' + this.dataset._sort[0].split('-')[1] + ']').addClass("sortup"); + } + } this.trigger('list_view_loaded', data, this.grouped); }, sort_by_column: function (e) { e.stopPropagation(); var $column = $(e.currentTarget); - this.dataset.sort($column.data('id')); + var col_name = $column.data('id') + var field = this.fields_view.fields[col_name]; + // test if the field is a function field with store=false, since it's impossible + // for the server to sort those fields we desactivate the feature + if (field && field.store === false) { + return false; + } + this.dataset.sort(col_name); if($column.hasClass("sortdown") || $column.hasClass("sortup")) { $column.toggleClass("sortup sortdown"); } else { diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 4a7c1aff69c..9fd49367171 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -285,14 +285,15 @@ instance.web.ActionManager = instance.web.Widget.extend({ var type = action.type.replace(/\./g,'_'); var popup = action.target === 'new'; var inline = action.target === 'inline' || action.target === 'inlineview'; - action.flags = _.extend({ + action.flags = _.defaults(action.flags || {}, { views_switcher : !popup && !inline, search_view : !popup && !inline, action_buttons : !popup && !inline, sidebar : !popup && !inline, pager : !popup && !inline, - display_title : !popup - }, action.flags || {}); + display_title : !popup, + search_disable_custom_filters: action.context && action.context.search_disable_custom_filters + }); action.menu_id = options.action_menu_id; if (!(type in this)) { console.error("Action manager can't handle action of type " + action.type, action); @@ -526,7 +527,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ } if (this.searchview) { - this.searchview[(view.controller.searchable === false || this.searchview.hidden) ? 'hide' : 'show'](); + this.searchview[(view.controller.searchable === false || this.searchview.options.hidden) ? 'hide' : 'show'](); } this.$el.find('.oe_view_manager_switch a').parent().removeClass('active'); @@ -684,7 +685,11 @@ instance.web.ViewManager = instance.web.Widget.extend({ if (this.searchview) { this.searchview.destroy(); } - this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, this.flags.search_view === false); + var options = { + hidden: this.flags.search_view === false, + disable_custom_filters: this.flags.search_disable_custom_filters, + }; + this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, options); this.searchview.on('search_data', self, this.do_searchview_search); return this.searchview.appendTo(this.$el.find(".oe_view_manager_view_search")); @@ -1265,6 +1270,11 @@ instance.web.View = instance.web.Widget.extend({ active_ids: [record_id], active_model: dataset.model }); + if (("" + action.context).match(/\bactive_id\b/)) { + // Special case: when the context is evaluted using + // the active_id, we want to disable the custom filters. + ncontext.add({ search_disable_custom_filters: true }); + } } ncontext.add(action.context || {}); action.context = ncontext; diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index b3f2364b42b..6d707bb4627 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -385,7 +385,9 @@ t-att-data-menu="menu.id" t-att-data-action-model="menu.action ? menu.action.split(',')[0] : ''" t-att-data-action-id="menu.action ? menu.action.split(',')[1] : ''"> - + + + diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js index 055180f004b..0e1c1351b98 100644 --- a/addons/web/static/test/evals.js +++ b/addons/web/static/test/evals.js @@ -282,7 +282,7 @@ openerp.testing.section('eval.edc', { db: '3', login: user.login, uid: user.id, - context: { + user_context: { uid: user.id, lang: user.lang, tz: user.tz diff --git a/addons/web_gantt/static/src/js/gantt.js b/addons/web_gantt/static/src/js/gantt.js index dbe5a33fcca..e6b12038126 100644 --- a/addons/web_gantt/static/src/js/gantt.js +++ b/addons/web_gantt/static/src/js/gantt.js @@ -136,7 +136,7 @@ instance.web_gantt.GanttView = instance.web.View.extend({ }); return group; } else { - var group = new GanttTaskInfo(_.uniqueId("gantt_project_task_"), group_name, task_start, duration, 100); + var group = new GanttTaskInfo(_.uniqueId("gantt_project_task_"), group_name, task_start, duration || 1, 100); _.each(task_infos, function(el) { group.addChildTask(el.task_info); }); @@ -161,7 +161,7 @@ instance.web_gantt.GanttView = instance.web.View.extend({ } var duration = (task_stop.getTime() - task_start.getTime()) / (1000 * 60 * 60); var id = _.uniqueId("gantt_task_"); - var task_info = new GanttTaskInfo(id, task_name, task_start, ((duration / 24) * 8), 100); + var task_info = new GanttTaskInfo(id, task_name, task_start, ((duration / 24) * 8) || 1, 100); task_info.internal_task = task; task_ids[id] = task_info; return {task_info: task_info, task_start: task_start, task_stop: task_stop}; @@ -195,6 +195,8 @@ instance.web_gantt.GanttView = instance.web.View.extend({ $(rendered).prependTo(td); $(".oe_gantt_button_create", this.$el).click(this.on_task_create); } + // Fix for IE to display the content of gantt view. + this.$el.find(".oe_gantt td:first > div, .oe_gantt td:eq(1) > div > div").css("overflow", ""); }, on_task_changed: function(task_obj) { var self = this; diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 9026251acea..3083a9e30a5 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -5,6 +5,7 @@ } .openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_dummy_cell { background: url(/web/static/src/img/form_sheetbg.png); + width: 100%; } .openerp .oe_kanban_view .ui-sortable-placeholder { border: 1px solid rgba(0, 0, 0, 0.1); @@ -32,7 +33,7 @@ clear: both; } .openerp .oe_kanban_view .oe_kanban_content { - word-break: break-all; + word-wrap: break-word; } .openerp .oe_kanban_view .oe_kanban_content .oe_star_on, .openerp .oe_kanban_view .oe_kanban_content .oe_star_off { color: #cccccc; @@ -77,13 +78,37 @@ font-size: 13px; } .openerp .oe_kanban_view .oe_kanban_group_title { + position: relative; font-size: 16px; font-weight: bold; color: #333333; text-shadow: 0 1px 0 white; + margin-right: 30px; + width: 200px; } -.openerp .oe_kanban_view .oe_kanban_group_title > span { +.openerp .oe_kanban_view .oe_kanban_group_title .oe_kanban_group_title_text { margin-right: 4px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.openerp .oe_kanban_view .oe_kanban_group_title .oe_kanban_group_length { + position: absolute; + top: -1px; + right: -14px; + text-align: center; + float: right; +} +.openerp .oe_kanban_view .oe_kanban_header:hover .oe_kanban_group_length { + display: none; +} +.openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_column, .openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_group_header { + width: 185px; + min-width: 185px; +} +.openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_column.oe_kanban_group_folded, .openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_group_header.oe_kanban_group_folded { + width: auto; + min-width: 30px; } .openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_group_header { vertical-align: top; @@ -102,9 +127,6 @@ border-left: 1px solid #f0f8f8; border-right: 1px solid #b9b9b9; } -.openerp .oe_kanban_view.oe_kanban_grouped .oe_kanban_group_header { - width: 1%; -} .openerp .oe_kanban_view .oe_form .oe_kanban_column { padding: 0px; background: white; @@ -165,7 +187,7 @@ margin: 4px 0; } .openerp .oe_kanban_view .oe_kanban_no_group .oe_kanban_quick_create { - width: 200px; + width: 185px; padding: 10px; } .openerp .oe_kanban_view .oe_kanban_quick_create input { @@ -432,6 +454,14 @@ line-height: 12px; font-size: 22px; } +.openerp .oe_kanban_view .oe_kanban_footer_left .oe_tags { + margin-right: 0; +} +.openerp .oe_kanban_view .oe_kanban_footer_left .oe_tags .oe_tag { + display: inline-block; + padding: 0 2px; + line-height: 14px; +} .openerp .oe_kanban_view .oe_kanban_footer_left .oe_kanban_mail_new { line-height: 18px; background-color: #8a89ba; diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index d6734124def..988dee01051 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -53,6 +53,7 @@ height: inherit &.oe_kanban_grouped .oe_kanban_dummy_cell background: url(/web/static/src/img/form_sheetbg.png) + width: 100% .ui-sortable-placeholder border: 1px solid rgba(0,0,0,0.1) visibility: visible !important @@ -69,7 +70,7 @@ .oe_kanban_clear clear: both .oe_kanban_content - word-break: break-all + word-wrap: break-word .oe_star_on, .oe_star_off color: #ccc text-shadow: 0 0 2px black @@ -105,12 +106,31 @@ font-weight: normal font-size: 13px .oe_kanban_group_title + position: relative font-size: 16px font-weight: bold color: #333333 text-shadow: 0 1px 0 white - > span + margin-right: 30px + width: 200px + .oe_kanban_group_title_text margin-right: 4px + white-space: nowrap + overflow: hidden + text-overflow: ellipsis + .oe_kanban_group_length + position: absolute + top: -1px + right: -14px + text-align: center + float: right + &.oe_kanban_grouped + .oe_kanban_column, .oe_kanban_group_header + width: 185px + min-width: 185px + &.oe_kanban_group_folded + width: auto + min-width: 30px .oe_kanban_column, .oe_kanban_group_header vertical-align: top @@ -126,10 +146,6 @@ background: #f0eeee border-left: 1px solid #f0f8f8 border-right: 1px solid #b9b9b9 - &.oe_kanban_grouped - .oe_kanban_group_header - width: 1% - .oe_form .oe_kanban_column padding: 0px @@ -182,7 +198,7 @@ .oe_kanban_quick_create_buttons margin: 4px 0 .oe_kanban_no_group .oe_kanban_quick_create - width: 200px + width: 185px padding: 10px .oe_kanban_quick_create input @include box-sizing(border-box) @@ -233,8 +249,9 @@ .oe_kanban_title font-weight: bold margin: 2px 4px - &.oe_kanban_grouped .oe_kanban_record - margin-bottom: 4px + &.oe_kanban_grouped + .oe_kanban_record + margin-bottom: 4px .oe_kanban_avatar_smallbox height: 40px width: 40px @@ -381,6 +398,12 @@ .oe_e line-height: 12px font-size: 22px + .oe_tags + margin-right: 0 + .oe_tag + display: inline-block + padding: 0 2px + line-height: 14px .oe_kanban_mail_new line-height: 18px background-color: #8a89ba diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 26526f85040..1d9ced0ca6d 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -235,7 +235,6 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ self.$el.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o); var grouping = new instance.web.Model(self.dataset.model, context, domain).query().group_by(self.group_by); $.when(grouping).done(function(groups) { - self.do_clear_groups(); if (groups) { self.do_process_groups(groups); } else { @@ -248,6 +247,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var self = this; this.$el.removeClass('oe_kanban_ungrouped').addClass('oe_kanban_grouped'); this.add_group_mutex.exec(function() { + self.do_clear_groups(); self.dataset.ids = []; if (!groups.length) { self.no_result(); @@ -275,6 +275,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.$el.removeClass('oe_kanban_grouped').addClass('oe_kanban_ungrouped'); this.add_group_mutex.exec(function() { var def = $.Deferred(); + self.do_clear_groups(); self.dataset.read_slice(self.fields_keys.concat(['__last_update']), { 'limit': self.limit }).done(function(records) { var kgroup = new instance.web_kanban.KanbanGroup(self, records, null, self.dataset); self.do_add_groups([kgroup]).done(function() { @@ -322,7 +323,6 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ }, on_groups_started: function() { var self = this; - this.compute_groups_width(); if (this.group_by) { // Kanban cards drag'n'drop var $columns = this.$el.find('.oe_kanban_column .oe_kanban_column_cards'); @@ -420,27 +420,6 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ }); } }, - compute_groups_width: function() { - var unfolded = 0; - var self = this; - _.each(this.groups, function(group) { - unfolded += group.state.folded ? 0 : 1; - group.$el.children(':first').css('width', ''); - }); - _.each(this.groups, function(group) { - if (!group.state.folded) { - if (182*unfolded>=self.$el.width()) { - group.$el.children(':first').css('width', "170px"); - } else if (262*unfolded
- - +
99+ - +
+