summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorThibault Delavallée <tde@openerp.com>2012-12-10 13:54:23 +0100
committerThibault Delavallée <tde@openerp.com>2012-12-10 13:54:23 +0100
commit1ca5e68b1f3ddb440b104c6c47ea35e8d26a1eed (patch)
tree4070b56d1253290fa69f4fbc43ad4862c883080e /addons/web/static/src
parenta5ca416f055871fb2765567c2cf2f06445c1d2ca (diff)
parent70f8f99b35c93a880cf15a1f21b7f88aef5a8d36 (diff)
[MERGE] Sync with trunk.
bzr revid: tde@openerp.com-20121130093732-i8y10ayjqiaq5t7p bzr revid: tde@openerp.com-20121204142854-pauouyapnw7z8zwj bzr revid: tde@openerp.com-20121205101544-k4ui6thr0ibzw0vx bzr revid: tde@openerp.com-20121210125423-81wbh4af9sxdqjki
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/css/base.css17
-rw-r--r--addons/web/static/src/css/base.sass15
-rw-r--r--addons/web/static/src/js/boot.js2
-rw-r--r--addons/web/static/src/js/chrome.js49
-rw-r--r--addons/web/static/src/js/corelib.js3
-rw-r--r--addons/web/static/src/js/coresetup.js2
-rw-r--r--addons/web/static/src/js/pyeval.js30
-rw-r--r--addons/web/static/src/js/search.js6
-rw-r--r--addons/web/static/src/js/testing.js4
-rw-r--r--addons/web/static/src/js/view_form.js48
-rw-r--r--addons/web/static/src/js/view_list.js19
-rw-r--r--addons/web/static/src/js/view_list_editable.js11
-rw-r--r--addons/web/static/src/js/view_tree.js14
-rw-r--r--addons/web/static/src/js/views.js87
-rw-r--r--addons/web/static/src/xml/base.xml13
15 files changed, 194 insertions, 126 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index a71a071db3b..0a4e2ad322f 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -652,7 +652,7 @@
cursor: pointer;
}
.openerp .oe_dropdown_toggle {
- color: #4C4C4C;
+ color: #4c4c4c;
font-weight: normal;
}
.openerp .oe_dropdown_hover:hover .oe_dropdown_menu, .openerp .oe_dropdown_menu.oe_opened {
@@ -795,6 +795,20 @@
.openerp .oe_notification {
z-index: 1050;
}
+.openerp .oe_webclient_timezone_notification a {
+ color: white;
+ text-decoration: underline;
+}
+.openerp .oe_webclient_timezone_notification p {
+ margin-top: 1em;
+}
+.openerp .oe_webclient_timezone_notification dt {
+ font-weight: bold;
+}
+.openerp .oe_timezone_systray span {
+ margin-top: 1px;
+ background-color: #f6cf3b;
+}
.openerp .oe_login {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAKUlEQVQIHWO8e/fufwYsgAUkJigoiCIF5DMyoYggcUiXgNnBiGQKmAkARpcEQeriln4AAAAASUVORK5CYII=);
text-align: center;
@@ -2249,6 +2263,7 @@
.openerp .oe_form .oe_form_field_url button img {
vertical-align: top;
}
+.openerp .oe_form .oe_form_field_monetary,
.openerp .oe_form .oe_form_field_date,
.openerp .oe_form .oe_form_field_datetime {
white-space: nowrap;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index f634452a7ee..e1789b0524c 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -671,9 +671,21 @@ $sheet-padding: 16px
border-bottom-right-radius: 8px
border-bottom-left-radius: 8px
// }}}
- // Notification {{{
+ // Notifications {{{
.oe_notification
z-index: 1050
+ .oe_webclient_timezone_notification
+ a
+ color: white
+ text-decoration: underline
+ p
+ margin-top: 1em
+ dt
+ font-weight: bold
+ .oe_timezone_systray
+ span
+ margin-top: 1px
+ background-color: #f6cf3b
// }}}
// Login {{{
.oe_login
@@ -1788,6 +1800,7 @@ $sheet-padding: 16px
border-left: 8px solid #eee
.oe_form_field_url button img
vertical-align: top
+ .oe_form_field_monetary,
.oe_form_field_date,
.oe_form_field_datetime
white-space: nowrap
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 5d50841d78d..4565d220dc8 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -22,7 +22,7 @@
* @param {Array|String} modules list of modules to initialize
*/
init: function(modules) {
- if (modules === "fuck your shit, don't load anything you cunt") {
+ if (modules === null) {
modules = [];
} else {
modules = _.union(['web'], modules || []);
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index c6d216d128c..55e14d6d783 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -830,7 +830,7 @@ instance.web.Menu = instance.web.Widget.extend({
this.renderElement();
this.limit_entries();
// Hide toplevel item if there is only one
- var $toplevel = this.$("li")
+ var $toplevel = this.$("li");
if($toplevel.length == 1) {
$toplevel.hide();
}
@@ -1125,7 +1125,6 @@ instance.web.WebClient = instance.web.Client.extend({
start: function() {
var self = this;
return $.when(this._super()).then(function() {
- self.$(".oe_logo").attr("href", $.param.fragment("" + window.location, "", 2).slice(0, -1));
if (jQuery.param !== undefined && jQuery.deparam(jQuery.param.querystring()).kitten !== undefined) {
$("body").addClass("kitten-mode-activated");
if ($.blockUI) {
@@ -1186,26 +1185,32 @@ instance.web.WebClient = instance.web.Client.extend({
},
check_timezone: function() {
var self = this;
- var user_offset = instance.session.user_context.tz_offset;
- var offset = -(new Date().getTimezoneOffset());
- // _.str.sprintf()'s zero front padding is buggy with signed decimals, so doing it manually
- var browser_offset = (offset < 0) ? "-" : "+";
- browser_offset += _.str.sprintf("%02d", Math.abs(offset / 60));
- browser_offset += _.str.sprintf("%02d", Math.abs(offset % 60));
- if (browser_offset !== user_offset) {
- var notification = this.do_warn(_t("Timezone"), QWeb.render('WebClient.timezone_notification', {
- user_timezone: instance.session.user_context.tz || 'UTC',
- user_offset: user_offset,
- browser_offset: browser_offset,
- }), true);
- notification.element.find('.oe_webclient_timezone_notification').on('click', function() {
- notification.close();
- }).find('a').on('click', function() {
- notification.close();
- self.user_menu.on_menu_settings();
- return false;
- });
- }
+ return new instance.web.Model('res.users').call('read', [[this.session.uid], ['tz_offset']]).then(function(result) {
+ var user_offset = result[0]['tz_offset'];
+ var offset = -(new Date().getTimezoneOffset());
+ // _.str.sprintf()'s zero front padding is buggy with signed decimals, so doing it manually
+ var browser_offset = (offset < 0) ? "-" : "+";
+ browser_offset += _.str.sprintf("%02d", Math.abs(offset / 60));
+ browser_offset += _.str.sprintf("%02d", Math.abs(offset % 60));
+ if (browser_offset !== user_offset) {
+ var $icon = $(QWeb.render('WebClient.timezone_systray'));
+ $icon.on('click', function() {
+ var notification = self.do_warn(_t("Timezone mismatch"), QWeb.render('WebClient.timezone_notification', {
+ user_timezone: instance.session.user_context.tz || 'UTC',
+ user_offset: user_offset,
+ browser_offset: browser_offset,
+ }), true);
+ notification.element.find('.oe_webclient_timezone_notification').on('click', function() {
+ notification.close();
+ }).find('a').on('click', function() {
+ notification.close();
+ self.user_menu.on_menu_settings();
+ return false;
+ });
+ });
+ $icon.appendTo(self.$('.oe_systray'));
+ }
+ });
},
destroy_content: function() {
_.each(_.clone(this.getChildren()), function(el) {
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index 55984162a55..f7a84e608c6 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -969,6 +969,9 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
if (_.isString(url)) {
url = { url: url };
}
+ _.defaults(params, {
+ context: this.user_context || {}
+ });
// Construct a JSON-RPC2 request, method is currently unused
if (this.debug)
params.debug = 1;
diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js
index fa1348a5f8c..74c30334e1e 100644
--- a/addons/web/static/src/js/coresetup.js
+++ b/addons/web/static/src/js/coresetup.js
@@ -622,7 +622,7 @@ var messages_by_seconds = function() {
[120, _t("Don't leave yet,<br />it's still loading...")],
[300, _t("You may not believe it,<br />but the application is actually loading...")],
[420, _t("Take a minute to get a coffee,<br />because it's loading...")],
- [3600, _t("Maybe you should consider reloading the application by pressing F5...")],
+ [3600, _t("Maybe you should consider reloading the application by pressing F5...")]
];
};
diff --git a/addons/web/static/src/js/pyeval.js b/addons/web/static/src/js/pyeval.js
index 265449f9f64..2c1b5ec9d7d 100644
--- a/addons/web/static/src/js/pyeval.js
+++ b/addons/web/static/src/js/pyeval.js
@@ -24,7 +24,7 @@ openerp.web.pyeval = function (instance) {
var mod = a%b;
// in python, sign(a % b) === sign(b). Not in JS. If wrong side, add a
// round of b
- if (mod > 0 && b < 0 || mod < 0 && b > 0) {
+ if (mod > 0 && b < 0 || mod < 0 && b > 0) {
mod += b;
}
return fn(Math.floor(a/b), mod);
@@ -398,14 +398,9 @@ openerp.web.pyeval = function (instance) {
now: py.classmethod.fromJSON(function () {
var d = new Date();
return py.PY_call(datetime.datetime,
- [d.getFullYear(), d.getMonth() + 1, d.getDate(),
- d.getHours(), d.getMinutes(), d.getSeconds(),
- d.getMilliseconds() * 1000]);
- }),
- today: py.classmethod.fromJSON(function () {
- var d = new Date();
- return py.PY_call(datetime.datetime,
- [d.getFullYear(), d.getMonth() + 1, d.getDate()]);
+ [d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(),
+ d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(),
+ d.getUTCMilliseconds() * 1000]);
}),
combine: py.classmethod.fromJSON(function () {
var args = py.PY_parseArgs(arguments, 'date time');
@@ -439,11 +434,6 @@ openerp.web.pyeval = function (instance) {
throw new Error('ValueError: No known conversion for ' + m);
}));
},
- today: py.classmethod.fromJSON(function () {
- var d = new Date();
- return py.PY_call(
- datetime.date, [d.getFullYear(), d.getMonth() + 1, d.getDate()]);
- }),
__eq__: function (other) {
return (this.year === other.year
&& this.month === other.month
@@ -479,6 +469,17 @@ openerp.web.pyeval = function (instance) {
return py.PY_call(datetime.date, [year, month, day])
}
});
+ /**
+ Returns the current local date, which means the date on the client (which can be different
+ compared to the date of the server).
+
+ @return {datetime.date}
+ */
+ var context_today = function() {
+ var d = new Date();
+ return py.PY_call(
+ datetime.date, [d.getFullYear(), d.getMonth() + 1, d.getDate()]);
+ };
datetime.time = py.type('time', null, {
__init__: function () {
var zero = py.float.fromJSON(0);
@@ -691,6 +692,7 @@ openerp.web.pyeval = function (instance) {
return {
uid: py.float.fromJSON(instance.session.uid),
datetime: datetime,
+ context_today: context_today,
time: time,
relativedelta: relativedelta,
current_date: py.PY_call(
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 3917f342391..eea8bba726d 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -341,12 +341,10 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
if (this.headless) {
this.ready.resolve();
} else {
- var load_view = this.rpc("/web/view/load", {
- model: this.model,
+ var load_view = instance.web.fields_view_get({
+ model: this.dataset._model,
view_id: this.view_id,
view_type: 'search',
- context: instance.web.pyeval.eval(
- 'context', this.dataset.get_context())
});
$.when(load_view).then(function (r) {
diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js
index 5aeeeb4de78..e7aad43ffc7 100644
--- a/addons/web/static/src/js/testing.js
+++ b/addons/web/static/src/js/testing.js
@@ -10,7 +10,7 @@ openerp.testing = {};
formats: ['coresetup', 'dates'],
chrome: ['corelib', 'coresetup'],
views: ['corelib', 'coresetup', 'data', 'chrome'],
- search: ['data', 'coresetup', 'formats'],
+ search: ['views', 'formats'],
list: ['views', 'data'],
form: ['data', 'views', 'list', 'formats'],
list_editable: ['list', 'form', 'data'],
@@ -263,7 +263,7 @@ openerp.testing = {};
++di;
}
- instance = openerp.init("fuck your shit, don't load anything you cunt");
+ instance = openerp.init(null);
_(d).chain()
.reverse()
.uniq()
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index ac76354b571..814995da5f7 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -1189,36 +1189,19 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
});
}
},
- view_arch_to_dom_node: function(arch) {
- // Historic mess for views arch
- //
- // server:
- // -> got xml as string
- // -> parse to xml and manipulate domains and contexts
- // -> convert to json
- // client:
- // -> got view as json
- // -> convert back to xml as string
- // -> parse it as xml doc (manipulate button@type for IE)
- // -> convert back to string
- // -> parse it as dom element with jquery
- // -> for each widget, convert node to json
- //
- // Wow !!!
- var xml = instance.web.json_node_to_xml(arch);
-
- var doc = $.parseXML('<div class="oe_form">' + xml + '</div>');
+ get_arch_fragment: function() {
+ var doc = $.parseXML(instance.web.json_node_to_xml(this.fvg.arch)).documentElement;
+ // IE won't allow custom button@type and will revert it to spec default : 'submit'
$('button', doc).each(function() {
$(this).attr('data-button-type', $(this).attr('type')).attr('type', 'button');
});
- xml = instance.web.xml_to_str(doc);
- return $(xml);
+ return $('<div class="oe_form"/>').append(instance.web.xml_to_str(doc));
},
render_to: function($target) {
var self = this;
this.$target = $target;
- this.$form = this.view_arch_to_dom_node(this.fvg.arch);
+ this.$form = this.get_arch_fragment();
this.process_version();
@@ -2680,13 +2663,10 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan
init: function(field_manager, node) {
var self = this;
this._super(field_manager, node);
- this.values = _.clone(this.field.selection);
- _.each(this.values, function(v, i) {
- if (v[0] === false && v[1] === '') {
- self.values.splice(i, 1);
- }
- });
- this.values.unshift([false, '']);
+ this.values = _(this.field.selection).chain()
+ .reject(function (v) { return v[0] === false && v[1] === ''; })
+ .unshift([false, ''])
+ .value();
},
initialize_content: function() {
// Flag indicating whether we're in an event chain containing a change
@@ -2930,6 +2910,15 @@ instance.web.form.M2ODialog = instance.web.Dialog.extend({
instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instance.web.form.CompletionFieldMixin, instance.web.form.ReinitializeFieldMixin, {
template: "FieldMany2One",
+ events: {
+ 'keydown input': function (e) {
+ switch (e.which) {
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.DOWN:
+ e.stopPropagation();
+ }
+ }
+ },
init: function(field_manager, node) {
this._super(field_manager, node);
instance.web.form.CompletionFieldMixin.init.call(this);
@@ -5260,6 +5249,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
instance.web.form.FieldMonetary = instance.web.form.FieldFloat.extend({
template: "FieldMonetary",
+ widget_class: 'oe_form_field_float oe_form_field_monetary',
init: function() {
this._super.apply(this, arguments);
this.set({"currency": false});
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 5008d1765a6..04ff8b48923 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -600,6 +600,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
this.dataset.index = _(this.dataset.ids).indexOf(ids[0]);
if (this.sidebar) {
+ this.options.$sidebar.show();
this.sidebar.$el.show();
}
@@ -922,6 +923,18 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
}, this);
this.$current = $('<tbody>')
+ .delegate('input[readonly=readonly]', 'click', function (e) {
+ /*
+ Against all logic and sense, as of right now @readonly
+ apparently does nothing on checkbox and radio inputs, so
+ the trick of using @readonly to have, well, readonly
+ checkboxes (which still let clicks go through) does not
+ work out of the box. We *still* need to preventDefault()
+ on the event, otherwise the checkbox's state *will* toggle
+ on click
+ */
+ e.preventDefault();
+ })
.delegate('th.oe_list_record_selector', 'click', function (e) {
e.stopPropagation();
var selection = self.get_selection();
@@ -939,12 +952,18 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web.
field = $target.closest('td').data('field'),
$row = $target.closest('tr'),
record_id = self.row_id($row);
+
+ if ($target.attr('disabled')) {
+ return;
+ }
+ $target.attr('disabled', 'disabled');
// note: $.data converts data to number if it's composed only
// of digits, nice when storing actual numbers, not nice when
// storing strings composed only of digits. Force the action
// name to be a string
$(self).trigger('action', [field.toString(), record_id, function (id) {
+ $target.removeAttr('disabled');
return self.reload_record(self.records.get(id));
}]);
})
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index 83a7efa6cd0..efc442de2a9 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -105,8 +105,15 @@ openerp.web.list_editable = function (instance) {
* Replace do_search to handle editability process
*/
do_search: function(domain, context, group_by) {
- this._context_editable = !!context.set_editable;
- this._super.apply(this, arguments);
+ var self=this, _super = self._super, args=arguments;
+ var ready = this.editor.is_editing()
+ ? this.cancel_edition(true)
+ : $.when();
+
+ return ready.then(function () {
+ self._context_editable = !!context.set_editable;
+ return _super.apply(self, args);
+ });
},
/**
* Replace do_add_record to handle editability (and adding new record
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index 4d08da385fd..acac93f1842 100644
--- a/addons/web/static/src/js/view_tree.js
+++ b/addons/web/static/src/js/view_tree.js
@@ -9,6 +9,7 @@ var QWeb = instance.web.qweb,
instance.web.views.add('tree', 'instance.web.TreeView');
instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeView# */{
display_name: _lt('Tree'),
+ view_type: 'tree',
/**
* Indicates that this view is not searchable, and thus that no search
* view should be displayed (if there is one active).
@@ -36,18 +37,9 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
this.options = _.extend({}, this.defaults, options || {});
_.bindAll(this, 'color_for');
+ this.on('view_loaded', this, this.load_tree);
},
- start: function () {
- 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,
- context: instance.web.pyeval.eval(
- 'context', this.dataset.get_context())
- }).done(this.on_loaded);
- },
/**
* Returns the list of fields needed to correctly read objects.
*
@@ -64,7 +56,7 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie
}
return fields;
},
- on_loaded: function (fields_view) {
+ load_tree: function (fields_view) {
var self = this;
var has_toolbar = !!fields_view.arch.attrs.toolbar;
// field name in OpenERP is kinda stupid: this is the name of the field
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index d7dcd590218..c0c6ae1f31d 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -275,7 +275,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
if (action.domain) {
action.domain = instance.web.pyeval.eval(
- 'domain', action.domain);
+ 'domain', action.domain, action.context || {});
}
if (!action.type) {
@@ -758,12 +758,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
dataset.index = 0;
}
this.dataset = dataset;
-
- // setup storage for session-wise menu hiding
- if (this.session.hidden_menutips) {
- return;
- }
- this.session.hidden_menutips = {};
},
/**
* Initializes the ViewManagerAction: sets up the searchview (if the
@@ -1204,13 +1198,11 @@ instance.web.View = instance.web.Widget.extend({
} else {
if (! this.view_type)
console.warn("view_type is not defined", this);
- view_loaded = this.rpc("/web/view/load", {
- "model": this.dataset.model,
+ view_loaded = instance.web.fields_view_get({
+ "model": this.dataset._model,
"view_id": this.view_id,
"view_type": this.view_type,
- toolbar: !!this.options.$sidebar,
- context: instance.web.pyeval.eval(
- 'context', this.dataset.get_context(context))
+ "toolbar": !!this.options.$sidebar,
});
}
return view_loaded.then(function(r) {
@@ -1385,12 +1377,53 @@ instance.web.View = instance.web.Widget.extend({
}
});
-instance.web.xml_to_json = function(node) {
+/**
+ * Performs a fields_view_get and apply postprocessing.
+ * return a {$.Deferred} resolved with the fvg
+ *
+ * @param {Object} [args]
+ * @param {String|Object} args.model instance.web.Model instance or string repr of the model
+ * @param {null|Object} args.context context if args.model is a string
+ * @param {null|Number} args.view_id id of the view to be loaded, default view if null
+ * @param {null|String} args.view_type type of view to be loaded if view_id is null
+ * @param {Boolean} [args.toolbar=false] get the toolbar definition
+ */
+instance.web.fields_view_get = function(args) {
+ function postprocess(fvg) {
+ var doc = $.parseXML(fvg.arch).documentElement;
+ fvg.arch = instance.web.xml_to_json(doc, (doc.nodeName.toLowerCase() !== 'kanban'));
+ if ('id' in fvg.fields) {
+ // Special case for id's
+ var id_field = fvg.fields['id'];
+ id_field.original_type = id_field.type;
+ id_field.type = 'id';
+ }
+ _.each(fvg.fields, function(field) {
+ _.each(field.views || {}, function(view) {
+ postprocess(view);
+ });
+ });
+ return fvg;
+ }
+ args = _.defaults(args, {
+ toolbar: false,
+ });
+ var model = args.model;
+ if (typeof model === 'string') {
+ model = new instance.web.Model(args.model, args.context);
+ }
+ return args.model.call('fields_view_get', [args.view_id, args.view_type, model.context(), args.toolbar]).then(function(fvg) {
+ return postprocess(fvg);
+ });
+};
+
+instance.web.xml_to_json = function(node, strip_whitespace) {
switch (node.nodeType) {
+ case 9:
+ return instance.web.xml_to_json(node.documentElement, strip_whitespace);
case 3:
case 4:
- return node.data;
- break;
+ return (strip_whitespace && node.data.trim() === '') ? undefined : node.data;
case 1:
var attrs = $(node).getAttributes();
_.each(['domain', 'filter_domain', 'context', 'default_get'], function(key) {
@@ -1403,7 +1436,9 @@ instance.web.xml_to_json = function(node) {
return {
tag: node.tagName.toLowerCase(),
attrs: attrs,
- children: _.map(node.childNodes, instance.web.xml_to_json)
+ children: _.compact(_.map(node.childNodes, function(node) {
+ return instance.web.xml_to_json(node, strip_whitespace);
+ })),
}
}
}
@@ -1455,26 +1490,6 @@ instance.web.xml_to_str = function(node) {
throw new Error(_t("Could not serialize XML"));
}
};
-instance.web.str_to_xml = function(s) {
- if (window.DOMParser) {
- var dp = new DOMParser();
- var r = dp.parseFromString(s, "text/xml");
- if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') {
- throw new Error(_t("Could not parse string to xml"));
- }
- return r;
- }
- var xDoc;
- try {
- xDoc = new ActiveXObject("MSXML2.DOMDocument");
- } catch (e) {
- throw new Error(_.str.sprintf( _t("Could not find a DOM Parser: %s"), e.message));
- }
- xDoc.async = false;
- xDoc.preserveWhiteSpace = true;
- xDoc.loadXML(s);
- return xDoc;
-}
/**
* Registry for all the main views
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 7421027315b..5ad24a43a6a 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -438,7 +438,8 @@
</tr>
<tr>
<td class="oe_leftbar" valign="top">
- <a class="oe_logo" href="#"><img t-att-src='_s + "/web/static/src/img/logo.png"'/></a>
+ <t t-set="debug" t-value="__debug__ ? '&amp;debug' : ''"/>
+ <a class="oe_logo" t-attf-href="/?ts=#{Date.now()}#{debug}"><img t-att-src='_s + "/web/static/src/img/logo.png"'/></a>
<div class="oe_secondary_menus_container"/>
<div class="oe_footer">
Powered by <a href="http://www.openerp.com" target="_blank"><span>OpenERP</span></a>
@@ -464,6 +465,11 @@
<p><a href="#">Click here to change your user's timezone.</a></p>
</div>
</t>
+<t t-name="WebClient.timezone_systray">
+ <div class="oe_topbar_item oe_timezone_systray" title="Timezone mismatch">
+ <span class="ui-icon ui-state-error ui-icon-alert"/>
+ </div>
+</t>
<t t-name="EmbedClient">
<div class="openerp">
@@ -1051,7 +1057,10 @@
t-att-autofocus="widget.node.attrs.autofocus"
t-att-id="widget.id_for_label">
<t t-foreach="widget.values" t-as="option">
- <option><t t-esc="widget.node.attrs.placeholder" t-if="option[0] == false and widget.node.attrs.placeholder"/><t t-esc="option[1]" t-if="option[0] != false"/></option>
+ <option>
+ <t t-esc="widget.node.attrs.placeholder" t-if="option[0] === false and widget.node.attrs.placeholder"/>
+ <t t-esc="option[1]" t-if="option[0] !== false"/>
+ </option>
</t>
</select>
</span>