summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorKunal Chavda (OpenERP) <kch@tinyerp.com>2011-10-17 16:07:40 +0530
committerKunal Chavda (OpenERP) <kch@tinyerp.com>2011-10-17 16:07:40 +0530
commitf76bdfb1fa4a2de837eacf619a211c805d23a226 (patch)
tree4bdcb2ef8e8b8e199b11574da215576f9ee29eef /addons/web/static/src
parentc5f5637e0992158734adda1782b725e24546dc6e (diff)
parentf1f48e69f0e654487234ced0537a03dd46fb3e12 (diff)
[MERGE]merge main view editor branch upto 884 revision.
bzr revid: kch@tinyerp.com-20111017103740-v7lrybz3gkq2ujxa
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/css/base.css20
-rw-r--r--addons/web/static/src/img/box-a-header-a.gifbin0 -> 91 bytes
-rw-r--r--addons/web/static/src/js/chrome.js75
-rw-r--r--addons/web/static/src/js/core.js14
-rw-r--r--addons/web/static/src/js/data.js172
-rw-r--r--addons/web/static/src/js/formats.js15
-rw-r--r--addons/web/static/src/js/search.js71
-rw-r--r--addons/web/static/src/js/view_editor.js575
-rw-r--r--addons/web/static/src/js/view_form.js504
-rw-r--r--addons/web/static/src/js/view_list.js87
-rw-r--r--addons/web/static/src/js/view_list_editable.js36
-rw-r--r--addons/web/static/src/js/view_tree.js42
-rw-r--r--addons/web/static/src/js/views.js272
-rw-r--r--addons/web/static/src/xml/base.xml83
14 files changed, 1190 insertions, 776 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index 7f5b7f5f41b..a814ddbba1b 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -300,7 +300,7 @@ label.error {
text-shadow: 0 1px 0 #333;
text-align: center;
font-size: 18px;
- line-height: 14px;
+ line-height: 18px;
right: 0;
}
.openerp .secondary_menu.oe_folded .oe_toggle_secondary_menu {
@@ -325,6 +325,7 @@ label.error {
background: #5A5858;
vertical-align: top;
height: 100%;
+ display: block;
position: relative;
}
.openerp .secondary_menu.oe_folded {
@@ -721,11 +722,15 @@ label.error {
.openerp .oe-listview .oe-field-cell {
cursor: pointer;
}
+.openerp .oe-listview .oe-field-cell progress {
+ width: 100%;
+}
.openerp .oe-listview .oe-field-cell button {
+ margin: 0;
padding: 0;
border: none;
background: none;
- width: 100%;
+ width: 16px;
}
.openerp .oe-listview .oe-field-cell button:active {
opacity: 0.5;
@@ -767,6 +772,10 @@ label.error {
.openerp .oe-listview .oe-list-footer span {
margin: 0 1em;
}
+.openerp .oe-listview .oe-list-footer progress {
+ vertical-align:-10% !important;
+ width: 100%;
+}
/** list rounded corners
@@ -828,6 +837,9 @@ label.error {
}
/* Form */
+.openerp .oe_frame.oe_forms {
+ clear: both;
+}
.openerp table.oe_frame td {
color: #4c4c4c;
}
@@ -855,7 +867,7 @@ label.error {
cursor: help;
}
-.openerp .oe_form_field label.oe_label, .openerp .oe_form_field label.oe_label_help {
+.openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help {
text-align: right;
margin: 3px 0 0 10px;
}
@@ -943,7 +955,7 @@ label.error {
position: relative;
}
.openerp input.oe-binary-file {
- z-index: 2;
+ z-index: 0;
line-height: 0;
font-size: 50px;
position: absolute;
diff --git a/addons/web/static/src/img/box-a-header-a.gif b/addons/web/static/src/img/box-a-header-a.gif
new file mode 100644
index 00000000000..6b461b42bfe
--- /dev/null
+++ b/addons/web/static/src/img/box-a-header-a.gif
Binary files differ
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 1955298ba27..69c9466a9ce 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -5,15 +5,16 @@ openerp.web.chrome = function(openerp) {
var QWeb = openerp.web.qweb;
openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Notification# */{
- /**
- * @constructs openerp.web.Notification
- * @extends openerp.web.Widget
- *
- * @param parent
- * @param element_id
- */
- init: function(parent, element_id) {
- this._super(parent, element_id);
+ template: 'Notification',
+ identifier_prefix: 'notification-',
+
+ init: function() {
+ this._super.apply(this, arguments);
+ openerp.notification = this;
+ },
+
+ start: function() {
+ this._super.apply(this, arguments);
this.$element.notify({
speed: 500,
expires: 1500
@@ -28,9 +29,12 @@ openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Not
warn: function(title, text) {
this.$element.notify('create', 'oe_notification_alert', {
title: title,
- text: text
+ text: text,
+ }, {
+ expires: false,
});
- }
+ },
+
});
openerp.web.Dialog = openerp.web.OldWidget.extend(/** @lends openerp.web.Dialog# */{
@@ -369,7 +373,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
}
$db_list.find(':selected').remove();
self.db_list.splice(_.indexOf(self.db_list, db, true), 1);
- self.notification.notify("Dropping database", "The database '" + db + "' has been dropped");
+ self.do_notify("Dropping database", "The database '" + db + "' has been dropped");
});
}
});
@@ -454,7 +458,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.display_error(result);
return;
}
- self.notification.notify("Changed Password", "Password has been changed successfully");
+ self.do_notify("Changed Password", "Password has been changed successfully");
});
}
});
@@ -462,7 +466,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
});
openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
- remember_creditentials: true,
+ remember_credentials: true,
template: "Login",
identifier_prefix: 'oe-app-login-',
@@ -480,13 +484,22 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
this.selected_db = null;
this.selected_login = null;
- if (this.has_local_storage && this.remember_creditentials) {
+ if (this.has_local_storage && this.remember_credentials) {
this.selected_db = localStorage.getItem('last_db_login_success');
this.selected_login = localStorage.getItem('last_login_login_success');
if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
this.selected_password = localStorage.getItem('last_password_login_success');
}
}
+
+ var qs = jQuery.deparam(jQuery.param.querystring());
+ if (qs.db) {
+ this.selected_db = qs.db;
+ }
+ if (qs.login) {
+ this.selected_login = qs.login;
+ }
+
},
start: function() {
var self = this;
@@ -537,7 +550,7 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
this.session.session_login(db, login, password, function() {
if(self.session.session_is_valid()) {
if (self.has_local_storage) {
- if(self.remember_creditentials) {
+ if(self.remember_credentials) {
localStorage.setItem('last_db_login_success', db);
localStorage.setItem('last_login_login_success', login);
if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
@@ -779,9 +792,8 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
},
start: function() {
this.$secondary_menu.addClass(this.folded ? 'oe_folded' : 'oe_unfolded');
- this.reload();
},
- reload: function() {
+ do_reload: function() {
this.rpc("/web/menu/load", {}, this.on_loaded);
},
on_loaded: function(data) {
@@ -823,7 +835,9 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
this.session.active_id = id;
this.rpc('/web/menu/action', {'menu_id': id}, this.on_menu_action_loaded);
}
- ev.stopPropagation();
+ if (ev) {
+ ev.stopPropagation();
+ }
return false;
},
do_menu_click: function($clicked_menu, manual) {
@@ -866,6 +880,7 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
$sub_menu.hide();
return true;
}
+ return manual;
} else {
return true;
}
@@ -927,14 +942,12 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
}
this.$element.html(QWeb.render("Interface", params));
+ this.notification = new openerp.web.Notification();
this.session = new openerp.web.Session();
this.loading = new openerp.web.Loading(this,"oe_loading");
this.crashmanager = new openerp.web.CrashManager(this);
this.crashmanager.start();
- // Do you autorize this ? will be replaced by notify() in controller
- openerp.web.Widget.prototype.notification = new openerp.web.Notification(this, "oe_notification");
-
this.header = new openerp.web.Header(this);
this.login = new openerp.web.Login(this);
this.header.on_logout.add(this.login.on_logout);
@@ -954,12 +967,27 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
},
start: function() {
+ this._super.apply(this, arguments);
+ this.notification.prependTo(this.$element);
this.header.appendTo($("#oe_header"));
this.session.start();
this.login.appendTo($('#oe_login'));
this.menu.start();
},
+ do_reload: function() {
+ this.session.session_restore();
+ this.menu.do_reload();
+ },
+ do_notify: function() {
+ var n = this.notification;
+ n.notify.apply(n, arguments);
+ },
+ do_warn: function() {
+ var n = this.notification;
+ n.warn.apply(n, arguments);
+ },
on_logged: function() {
+ this.menu.do_reload();
if(this.action_manager)
this.action_manager.stop();
this.action_manager = new openerp.web.ActionManager(this);
@@ -1046,7 +1074,8 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
this.action_manager.do_action(action);
},
do_about: function() {
- }
+ },
+
});
};
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index 9d4d2124008..c3ff924c8e9 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -287,14 +287,12 @@ openerp.web.Registry = openerp.web.Class.extend( /** @lends openerp.web.Registry
*/
get_any: function (keys) {
for (var i=0; i<keys.length; ++i) {
- try {
- return this.get_object(keys[i]);
- } catch (e) {
- if (e instanceof openerp.web.KeyNotFound) {
- continue;
- }
- throw e;
+ var key = keys[i];
+ if (key === undefined || !(key in this.map)) {
+ continue;
}
+
+ return this.get_object(key);
}
throw new openerp.web.KeyNotFound(keys.join(','));
},
@@ -480,7 +478,7 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web
session_login: function(db, login, password, success_callback) {
var self = this;
var params = { db: db, login: login, password: password };
- this.rpc("/web/session/login", params, function(result) {
+ return this.rpc("/web/session/login", params, function(result) {
self.session_id = result.session_id;
self.uid = result.uid;
self.user_context = result.context;
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index fcf6a65dcf5..1eaffcd0e30 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -610,40 +610,120 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
on_default_get: function(res) {
this.last_default_get = res;
},
+ /**
+ * Makes sure this dataset has the fields_get for its model stored locally,
+ * so create/write methods are able to determine if written fields are m2os
+ * and can name_get those fields if that's the case (in order to cache a
+ * correct m2o value for them)
+ *
+ * @returns {$.Deferred} whether the fields_get is done executing, provides the fields_get value to its callbacks
+ */
+ ensure_has_fields: function () {
+ var self = this;
+
+ if (this.fields_get) {
+ var d = $.Deferred();
+ setTimeout(function () { d.resolve(self.fields_get, true); }, 0);
+ return d.promise();
+ } else {
+ return self.call('fields_get', [], function (fields_get) {
+ self.fields_get = fields_get;
+ });
+ }
+ },
+ /**
+ * Relational fields may not be written in the same format they are read.
+ *
+ * Since the BufferedDataSet is a bit dumb, it returns what it's got stored
+ * in its cache, which for modified value is what it was given. This breaks
+ * some basic contracts of openerp such as m2o read being in the
+ * ``name_get`` format.
+ *
+ * Because create & write are supposed to be asynchronous, though, it
+ * should be easy to just name_get all incorrect values.
+ *
+ * @param {Object} data form-data to write to the cache
+ * @returns {$.Deferred} resolved with a fixed data dictionary
+ */
+ fix_relational: function (data) {
+ var self = this;
+ var results = $.Deferred();
+ this.ensure_has_fields().then(function (fields) {
+ var fields_to_fix = _(fields).chain()
+ .map(function (d, k) { return {key: k, descriptor: d}; })
+ .filter(function (field) {
+ // keep m2o fields which are in the data dict
+ return field.descriptor.type === 'many2one' &&
+ data[field.key];
+ }).pluck('key')
+ .value();
+ var name_gets = _(fields_to_fix).map(function (field) {
+ return new openerp.web.DataSet(self, self.fields_get[field].relation)
+ .name_get([data[field]], null);
+ });
+ // null-concat forces stupid bastard `when` to always return an
+ // array containing the Array-ified results of all the name_gets.
+ // otherwise, if there's a single field to fix it returns the
+ // results of the unique name_get directly.
+ $.when.apply(null, name_gets.concat([null])).then(function () {
+ var record = _.extend({}, data);
+ for(var i=0; i<fields_to_fix.length; ++i) {
+ // Each argument is [[name_get], success, jqXhr] and we
+ // want just the name_get pair
+ record[fields_to_fix[i]] = arguments[i][0][0];
+ }
+ results.resolve(record);
+ });
+ });
+ return results;
+ },
create: function(data, callback, error_callback) {
- var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data,
- defaults: this.last_default_get};
- this.to_create.push(cached);
- this.cache.push(cached);
- this.on_change();
+ var self = this;
var prom = $.Deferred().then(callback);
- setTimeout(function() {prom.resolve({result: cached.id});}, 0);
+ this.fix_relational(data).then(function (fixed_m2o_data) {
+ var cached = {
+ id:_.uniqueId(self.virtual_id_prefix),
+ values: fixed_m2o_data,
+ defaults: self.last_default_get
+ };
+ self.to_create.push(_.extend(_.clone(cached), {
+ values: _.clone(data)}));
+ self.cache.push(cached);
+ self.on_change();
+ prom.resolve({result: cached.id});
+ });
return prom.promise();
},
write: function (id, data, options, callback) {
var self = this;
- var record = _.detect(this.to_create, function(x) {return x.id === id;});
- record = record || _.detect(this.to_write, function(x) {return x.id === id;});
- var dirty = false;
- if (record) {
- for (var k in data) {
- if (record.values[k] === undefined || record.values[k] !== data[k]) {
- dirty = true;
- break;
+ var to_return = $.Deferred().then(callback);
+ this.fix_relational(data).then(function (fixed_m2o_data) {
+ var record = _.detect(self.to_create, function(x) {return x.id === id;});
+ record = record || _.detect(self.to_write, function(x) {return x.id === id;});
+ var dirty = false;
+ if (record) {
+ for (var k in data) {
+ if (record.values[k] === undefined || record.values[k] !== data[k]) {
+ dirty = true;
+ break;
+ }
}
+ _.extend(record.values, data);
+ } else {
+ dirty = true;
+ record = {id: id, values: data};
+ self.to_write.push(record);
}
- $.extend(record.values, data);
- } else {
- dirty = true;
- record = {id: id, values: data};
- self.to_write.push(record);
- }
- var cached = _.detect(this.cache, function(x) {return x.id === id;});
- $.extend(cached.values, record.values);
- if (dirty)
- this.on_change();
- var to_return = $.Deferred().then(callback);
- to_return.resolve({result: true});
+ var cached = _.detect(self.cache, function(x) {return x.id === id;});
+ if (!cached) {
+ cached = {id: id, values: {}};
+ this.cache.push(cached);
+ }
+ _.extend(cached.values, fixed_m2o_data);
+ if (dirty)
+ self.on_change();
+ to_return.resolve({result: true});
+ });
return to_return.promise();
},
unlink: function(ids, callback, error_callback) {
@@ -695,7 +775,7 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
throw "Record not correctly loaded";
}
}
- setTimeout(function () {completion.resolve(records);}, 0);
+ completion.resolve(records);
};
if(to_get.length > 0) {
var rpc_promise = this._super(to_get, fields, function(records) {
@@ -720,27 +800,51 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
});
openerp.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
-openerp.web.ReadOnlyDataSetSearch = openerp.web.DataSetSearch.extend({
+openerp.web.ProxyDataSet = openerp.web.DataSetSearch.extend({
+ init: function() {
+ this._super.apply(this, arguments);
+ this.create_function = null;
+ this.write_function = null;
+ this.read_function = null;
+ },
+ read_ids: function () {
+ if (this.read_function) {
+ return this.read_function.apply(null, arguments);
+ } else {
+ return this._super.apply(this, arguments);
+ }
+ },
default_get: function(fields, callback) {
return this._super(fields, callback).then(this.on_default_get);
},
on_default_get: function(result) {},
create: function(data, callback, error_callback) {
this.on_create(data);
- var to_return = $.Deferred().then(callback);
- setTimeout(function () {to_return.resolve({"result": undefined});}, 0);
- return to_return.promise();
+ if (this.create_function) {
+ return this.create_function(data, callback, error_callback);
+ } else {
+ console.warn("trying to create a record using default proxy dataset behavior");
+ var to_return = $.Deferred().then(callback);
+ setTimeout(function () {to_return.resolve({"result": undefined});}, 0);
+ return to_return.promise();
+ }
},
on_create: function(data) {},
write: function (id, data, options, callback) {
this.on_write(id, data);
- var to_return = $.Deferred().then(callback);
- setTimeout(function () {to_return.resolve({"result": true});}, 0);
- return to_return.promise();
+ if (this.write_function) {
+ return this.write_function(id, data, options, callback);
+ } else {
+ console.warn("trying to write a record using default proxy dataset behavior");
+ var to_return = $.Deferred().then(callback);
+ setTimeout(function () {to_return.resolve({"result": true});}, 0);
+ return to_return.promise();
+ }
},
on_write: function(id, data) {},
unlink: function(ids, callback, error_callback) {
this.on_unlink(ids);
+ console.warn("trying to unlink a record using default proxy dataset behavior");
var to_return = $.Deferred().then(callback);
setTimeout(function () {to_return.resolve({"result": true});}, 0);
return to_return.promise();
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index e7feedf26a5..94b2c7085db 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -69,6 +69,13 @@ openerp.web.format_value = function (value, descriptor, value_if_empty) {
} catch (e) {
return value.format("%H:%M:%S");
}
+ case 'selection':
+ // Each choice is [value, label]
+ var result = _(descriptor.selection).detect(function (choice) {
+ return choice[0] === value;
+ });
+ if (result) { return result[1]; }
+ return;
default:
return value;
}
@@ -179,9 +186,13 @@ openerp.web.auto_date_to_str = function(value, type) {
* @param {String} [column.string] button label
* @param {String} [column.icon] button icon
* @param {String} [value_if_empty=''] what to display if the field's value is ``false``
+ * @param {Boolean} [process_modifiers=true] should the modifiers be computed ?
*/
-openerp.web.format_cell = function (row_data, column, value_if_empty) {
- var attrs = column.modifiers_for(row_data);
+openerp.web.format_cell = function (row_data, column, value_if_empty, process_modifiers) {
+ var attrs = {};
+ if (process_modifiers !== false) {
+ attrs = column.modifiers_for(row_data);
+ }
if (attrs.invisible) { return ''; }
if (column.tag === 'button') {
return [
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index db91d6bfd27..2769a860d2a 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -13,24 +13,35 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
* @param view_id
* @param defaults
*/
- init: function(parent, dataset, view_id, defaults) {
+ init: function(parent, dataset, view_id, defaults, hidden) {
this._super(parent);
this.dataset = dataset;
this.model = dataset.model;
this.view_id = view_id;
this.defaults = defaults || {};
+ this.has_defaults = !_.isEmpty(this.defaults);
this.inputs = [];
this.enabled_filters = [];
this.has_focus = false;
+ this.hidden = !!hidden;
+ this.headless = this.hidden && !this.has_defaults;
+
this.ready = $.Deferred();
},
start: function() {
this._super();
- this.rpc("/web/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
+ if (this.hidden) {
+ this.$element.hide();
+ }
+ if (this.headless) {
+ this.ready.resolve();
+ } else {
+ this.rpc("/web/searchview/load", {"model": this.model, "view_id":this.view_id}, this.on_loaded);
+ }
return this.ready.promise();
},
show: function () {
@@ -105,8 +116,9 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
*/
make_field: function (item, field) {
try {
- return new (openerp.web.search.fields.get_object(field.type))
- (item, field, this);
+ return new (openerp.web.search.fields.get_any(
+ [item.attrs.widget, field.type]))
+ (item, field, this);
} catch (e) {
if (! e instanceof openerp.web.KeyNotFound) {
throw e;
@@ -137,10 +149,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
'defaults': this.defaults
});
- // We don't understand why the following commented line does not work in Chrome but
- // the non-commented line does. As far as we investigated, only God knows.
- //this.$element.html(render);
- jQuery(render).appendTo(this.$element);
+ this.$element.html(render);
this.$element.find(".oe_search-view-custom-filter-btn").click(ext.on_activate);
var f = this.$element.find('form');
@@ -246,10 +255,13 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
* @param e jQuery event object coming from the "Search" button
*/
do_search: function (e) {
+ if (this.headless && !this.has_defaults) {
+ return this.on_search([], [], []);
+ }
// reset filters management
var select = this.$element.find(".oe_search-view-filters-management");
select.val("_filters");
-
+
if (e && e.preventDefault) { e.preventDefault(); }
var data = this.build_search_data();
@@ -324,10 +336,10 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
* @param {Array} errors a never-empty array of error objects
*/
on_invalid: function (errors) {
- this.notification.notify("Invalid Search", "triggered from search view");
+ this.do_notify("Invalid Search", "triggered from search view");
},
do_clear: function () {
- this.$element.find('.filter_label').removeClass('enabled');
+ this.$element.find('.filter_label, .filter_icon').removeClass('enabled');
this.enabled_filters.splice(0);
var string = $('a.searchview_group_string');
_.each(string, function(str){
@@ -748,9 +760,44 @@ openerp.web.search.FloatField = openerp.web.search.NumberField.extend(/** @lends
* @extends openerp.web.search.Field
*/
openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends openerp.web.search.SelectionField# */{
+ // This implementation is a basic <select> field, but it may have to be
+ // altered to be more in line with the GTK client, which uses a combo box
+ // (~ jquery.autocomplete):
+ // * If an option was selected in the list, behave as currently
+ // * If something which is not in the list was entered (via the text input),
+ // the default domain should become (`ilike` string_value) but **any
+ // ``context`` or ``filter_domain`` becomes falsy, idem if ``@operator``
+ // is specified. So at least get_domain needs to be quite a bit
+ // overridden (if there's no @value and there is no filter_domain and
+ // there is no @operator, return [[name, 'ilike', str_val]]
template: 'SearchView.field.selection',
+ init: function () {
+ this._super.apply(this, arguments);
+ // prepend empty option if there is no empty option in the selection list
+ this.prepend_empty = !_(this.attrs.selection).detect(function (item) {
+ return !item[1];
+ });
+ },
get_value: function () {
- return this.$element.val();
+ var index = parseInt(this.$element.val(), 10);
+ if (isNaN(index)) { return null; }
+ var value = this.attrs.selection[index][0];
+ if (value === false) { return null; }
+ return value;
+ },
+ /**
+ * The selection field needs a default ``false`` value in case none is
+ * provided, so that selector options with a ``false`` value (convention
+ * for explicitly empty options) get selected by default rather than the
+ * first (value-holding) option in the selection.
+ *
+ * @param {Object} defaults search default values
+ */
+ render: function (defaults) {
+ if (!defaults[this.attrs.name]) {
+ defaults[this.attrs.name] = false;
+ }
+ return this._super(defaults);
}
});
openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @lends openerp.web.search.BooleanField# */{
diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js
index 87744825207..774d1872c29 100644
--- a/addons/web/static/src/js/view_editor.js
+++ b/addons/web/static/src/js/view_editor.js
@@ -32,241 +32,247 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
this.xml_id = 0;
this.property = openerp.web.ViewEditor.property_widget;
},
-
start: function() {
this.View_editor();
},
-
- View_editor : function(){
- var self = this;
- var action = {
- name:'ViewEditor',
- context:this.session.user_context,
- domain: [["model", "=", this.dataset.model]],
- res_model : 'ir.ui.view',
- views : [[false, 'list']],
- type: 'ir.actions.act_window',
- target: "current",
- limit : 80,
- auto_search : true,
- flags: {
- sidebar: false,
- views_switcher: false,
- action_buttons:false,
- search_view:false,
- pager:false,
- radio:true
- },
- };
- var action_manager = new openerp.web.ActionManager(this);
- this.dialog = new openerp.web.Dialog(this,{
- modal: true,
- title: 'ViewEditor',
- width: 750,
- height: 500,
- buttons: {
- "Create": function(){
- //to do
- },
- "Edit": function(){
- self.xml_id = 0 ;
- self.get_data();
+ View_editor : function() {
+ var self = this;
+ var action = {
+ name:'ViewEditor',
+ context:this.session.user_context,
+ domain: [["model", "=", this.dataset.model]],
+ res_model : 'ir.ui.view',
+ views : [[false, 'list']],
+ type: 'ir.actions.act_window',
+ target: "current",
+ limit : 80,
+ auto_search : true,
+ flags: {
+ sidebar: false,
+ views_switcher: false,
+ action_buttons:false,
+ search_view:false,
+ pager:false,
+ radio:true
+ },
+ };
+ var action_manager = new openerp.web.ActionManager(this);
+ this.view_edit_dialog = new openerp.web.Dialog(this,{
+ modal: true,
+ title: 'ViewEditor',
+ width: 750,
+ height: 500,
+ buttons: {
+ "Create": function(){
+ //to do
+ },
+ "Edit": function(){
+ self.xml_id = 0 ;
+ self.get_data();
+ },
+ "Close": function(){
+ $(this).dialog('destroy');
+ }
},
- "Close": function(){
- $(this).dialog('destroy');
- }
- },
- });
- this.dialog.start();
- this.dialog.open();
- action_manager.appendTo(this.dialog);
- action_manager.do_action(action);
+ });
+ this.view_edit_dialog.start();
+ this.view_edit_dialog.open();
+ action_manager.appendTo(this.view_edit_dialog);
+ action_manager.do_action(action);
},
-
- check_attr:function(xml,tag,level){
+ check_attr: function(xml, tag, level) {
var obj = new Object();
obj.child_id = [];
obj.id = this.xml_id++;
- obj.level = level;
- var vidhin = xml;
- var att_list = [];
+ obj.level = level+1;
var render_name = "<" + tag;
- var xml_tag = "<" + tag;
+ obj.att_list = [];
+ obj.att_list.push(tag);
$(xml).each(function() {
- att_list = this.attributes;
- att_list = _.select(att_list, function(attrs){
- xml_tag += ' ' +attrs.nodeName+'='+'"'+attrs.nodeValue+'"';
- if (tag != 'button'){
- if(attrs.nodeName == "string" || attrs.nodeName == "name" || attrs.nodeName == "index"){
- render_name += ' ' +attrs.nodeName+'='+'"'+attrs.nodeValue+'"';}
- }else{
- if(attrs.nodeName == "name"){
- render_name += ' ' +attrs.nodeName+'='+'"'+attrs.nodeValue+'"';}
- }
- });
- render_name+= ">";
- xml_tag+= ">";
+ _.each(this.attributes, function(attrs){
+ if (tag != 'button') {
+ if (attrs.nodeName == "string" || attrs.nodeName == "name" || attrs.nodeName == "index") {
+ render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"' ;
+ }
+ } else if (attrs.nodeName == "name") {
+ render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"';
+ }
+ if (attrs.nodeName != "position") {
+ obj.att_list.push( [attrs.nodeName,attrs.nodeValue] );
+ }
+ });
+ render_name+= ">";
});
- obj.main_xml = xml;
obj.name = render_name;
return obj;
},
-
- save_object : function(val,parent_list,child_obj_list){
+ save_object: function(val, parent_list, child_obj_list) {
var self = this;
var check_id = parent_list[0];
var p_list = parent_list.slice(1);
- if(val.child_id.length != 0){
- $.each(val.child_id, function(key,val) {
- if(val.id==check_id){
- if(p_list.length!=0){
- self.save_object(val,p_list,child_obj_list);
- }else{
+ if (val.child_id.length != 0) {
+ _.each(val.child_id, function(val, key) {
+ if (val.id==check_id) {
+ if (p_list.length!=0) {
+ self.save_object(val, p_list, child_obj_list);
+ } else {
val.child_id = child_obj_list;
- return;
+ return false;
}
}
});
- }else{
+ } else {
val.child_id = child_obj_list;
}
},
-
- children_function : function(xml,root,parent_list,parent_id,main_object,parent_child_id){
+ xml_node_create: function(xml, root, parent_list, parent_id, main_object){
var self = this;
var child_obj_list = [];
- var parent_child_id = parent_child_id;
- var parent_list = parent_list;
- var main_object = main_object;
var children_list = $(xml).filter(root).children();
var parents = $(children_list[0]).parents().get();
- _.each(children_list, function(child_node){
- var string = self.check_attr(child_node,child_node.tagName.toLowerCase(),parents.length);
- child_obj_list.push(string);
+ _.each(children_list, function (child_node) {
+ child_obj_list.push(self.check_attr(child_node,child_node.tagName.toLowerCase(),parents.length));
});
-
- if(children_list.length != 0){
- var child_ids = _.map(child_obj_list ,function(num){return num.id;});
- parent_child_id.push({'key': parent_id, 'value': child_ids});
- var parents = $(children_list[0]).parents().get();
- if(parents.length <= parent_list.length){
- parent_list.splice(parents.length-1);
+ if (children_list.length != 0) {
+ if (parents.length <= parent_list.length) {
+ parent_list.splice(parents.length - 1);
}
parent_list.push(parent_id);
- $.each(main_object, function(key,val) {
- self.save_object(val,parent_list.slice(1),child_obj_list);
- });
+ self.save_object(main_object[0], parent_list.slice(1), child_obj_list);
}
-
- for(var i=0;i<children_list.length;i++){
- self.children_function
- (children_list[i],children_list[i].tagName.toLowerCase(),
- parent_list,child_obj_list[i].id,main_object,parent_child_id);
+ for (var i=0; i<children_list.length; i++) {
+ self.xml_node_create
+ (children_list[i], children_list[i].tagName.toLowerCase(),
+ parent_list, child_obj_list[i].id, main_object);
}
- return {"main_object":main_object,"parent_child_id":parent_child_id};
+ return main_object;
},
-
- parse_xml :function(arch,view_id){
- var self = this;
+ parse_xml: function(arch, view_id) {
var root = $(arch).filter(":first")[0];
var tag = root.tagName.toLowerCase();
- var root_object = self.check_attr(root,tag,this.xml_id);
- return self.children_function(arch,tag,[],this.xml_id-1,[root_object],[]);
+ var obj ={'child_id':[],'id':this.xml_id++,'level':0,'att_list':[],'name':"<view view_id='"+view_id+"'>"};
+ var root_object = this.check_attr(root,tag,0);
+ obj.child_id = this.xml_node_create(arch, tag, [], this.xml_id-1, [root_object], [])
+ return [obj];
},
-
- get_data : function(){
+ get_data: function() {
var self = this;
- var view_id =(($("input[name='radiogroup']:checked").parent()).parent()).attr('data-id');
- var ve_dataset = new openerp.web.DataSet(this,'ir.ui.view');
- ve_dataset.read_ids([parseInt(view_id)],['arch'],function (arch){
+ var view_id =((this.view_edit_dialog.$element.find("input[name='radiogroup']:checked").parent()).parent()).attr('data-id');
+ var ve_dataset = new openerp.web.DataSet(this, 'ir.ui.view');
+ ve_dataset.read_ids([parseInt(view_id)], ['arch'], function (arch) {
one_object = self.parse_xml(arch[0].arch,view_id);
one_object.arch = arch[0].arch;
- dataset = new openerp.web.DataSetSearch(self,'ir.ui.view', null, null);
- dataset.read_slice([],{domain : [['inherit_id','=',parseInt(view_id)]]},function (result) {
- _.each(result,function(res){
- self.inherit_view(one_object,res);
+ dataset = new openerp.web.DataSetSearch(self, 'ir.ui.view', null, null);
+ dataset.read_slice([], {domain : [['inherit_id','=', parseInt(view_id)]]}, function (result) {
+ _.each(result, function(res) {
+ self.inherit_view(one_object, res);
});
- return self.edit_view(one_object);
+ return self.edit_view({"main_object": one_object,
+ "parent_child_id": self.parent_child_list(one_object, [])});
});
});
},
- inherit_view : function(one_object,result){
+ parent_child_list : function(one_object, p_list) {
+ var self = this;
+ _.each(one_object , function(element){
+ if(element.child_id.length != 0){
+ p_list.push({"key":element.id,"value":_.pluck(element.child_id, 'id')});
+ self.parent_child_list(element.child_id, p_list);
+ }
+ });
+ return p_list;
+ },
+ inherit_view : function(one_object, result) {
var self = this;
var root = $(result.arch).filter('*');
- var xpath_list = [];
- var part_expr = [];
- var position ;
- if(root[0].tagName.toLowerCase() == "data"){
- _.each($(root).find('xpath'),function(xpath){
- xpath_list.push(xpath);
- });
- } else if(root[0].tagName.toLowerCase() == "xpath"){
- xpath_list.push(root[0]);
+ var xml_list = [];
+ if (root[0].tagName.toLowerCase() == "data") {
+ xml_list = $(root[0]).children();
+ } else {
+ xml_list.push(root[0]);
}
- _.each(xpath_list,function(element){
- var xpath_object = self.parse_xml(element,result.id);
- var expr = $(element).attr('expr');
- var position = $(element).attr('position');
- part_expr = expr.split("/");
- if(part_expr[0]=="" && part_expr[1]==""){
- part_expr = part_expr.splice(2);
- }else if(part_expr[0]==""){
- part_expr = part_expr.splice(1);
- }
- if(part_expr[part_expr.length-1].search("@")!=-1){
- var part = part_expr[part_expr.length-1];
- var xpath_list = $.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,' ')).split(" ");
- one_object['parent_child_id'].push(xpath_object['parent_child_id'][0]);
- $.each(one_object['main_object'], function(key,val) {
- var id = self.search_object(val,xpath_list,[],position,xpath_object['main_object'],[]);
- _.detect(one_object['parent_child_id'],function(res){
- if(res.key==id){
- res.value.push(xpath_object['main_object'][0].id);
- }
- });
+ _.each(xml_list , function(xml){
+ var parent_id;
+ var check_list = [];
+ var xpath_object = self.parse_xml(xml,result.id);
+ if (xml.tagName.toLowerCase() == "xpath" ) {
+ var part_expr = _.without($(xml).attr('expr').split("/"),"");
+ _.each(part_expr,function(part){
+ check_list.push(_.without($.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,'!')).split("!"),""));
});
+ } else {
+ check_list = [_.flatten(xpath_object[0].child_id[0].att_list)];
}
+ self.full_path_search(check_list ,one_object ,xpath_object);
});
},
- search_object:function(val,list,p_list,position,xpath_object,r_list){
+ full_path_search: function(check_list ,val ,xpath_object) {
var self = this;
- var return_list = r_list;
- var main_list = $.trim(val.name.replace(/[^a-zA-Z 0-9 _]+/g,' ')).split(" ");
- var insert = _.intersection(main_list,list);
- var check = _.indexOf(p_list.child_id,xpath_object[0]);
- if(check == -1){
- if(insert.length == list.length){
- var level = val.level;
- $.each(xpath_object, function(key,val) {
- self.increase_level(val,level)
- });
- var index = _.indexOf(p_list.child_id,val);
- if(position == "before"){
- if(index!=0){index--;}
- }else if(position == "after"){
- index++;
+ if(xpath_object.length!=0){
+ var check = check_list[0];
+ var obj;
+ switch (check.length) {
+ case 2:
+ if(parseInt(check[1])){
+ var list_1 = _.select(val,function(element){
+ var main_list = _.flatten(element.att_list);
+ return _.include(main_list, check[0]);
+ });
+ obj = val[_.indexOf(val,list_1[parseInt(check[1])-1])];
+ } else {
+ obj = _.detect(val, function(element){
+ var main_list = _.flatten(element.att_list);
+ return _.include(main_list, check[0]);
+ });
+ }
+ break;
+ case 3:
+ obj = _.detect(val,function(element){
+ var main_list = _.flatten(element.att_list);
+ check = _.uniq(check);
+ var insert = _.intersection(main_list,check);
+ if(insert.length == check.length ){return element;}
+ });
+ break;
+ case 1:
+ var list_1 = _.select(val,function(element){
+ var main_list = _.flatten(element.att_list);
+ return _.include(main_list, check[0]);
+ });
+ if(list_1 != 0){
+ (check_list.length == 1)? obj = list_1[0] : check_list.shift();
+ }
+ break;
+ }
+ if(obj) {
+ check_list.shift();
+ if (check_list.length !=0){
+ self.full_path_search(check_list ,obj.child_id ,xpath_object);
+ } else {
+ var level = obj.level+1;
+ self.increase_level(xpath_object[0], level)
+ obj.child_id.push(xpath_object[0]);
+ xpath_object.pop();
+ return;
}
- p_list.child_id.splice(index,0,xpath_object[0]);
- return_list.push(p_list.id);
- }else{
- if(val.child_id.length!=0){p_list = val;}
- $.each(val.child_id, function(key,val) {
- self.search_object(val,list,p_list,position,xpath_object,return_list);
+ }
+ else {
+ _.each(val,function(element){
+ self.full_path_search(check_list ,element.child_id ,xpath_object);
});
}
}
- return return_list;
},
- increase_level :function(val,level){
+ increase_level: function(val, level) {
var self = this;
val.level = level;
- $.each(val.child_id, function(key,val) {
- self.increase_level(val,level+1);
+ _.each(val.child_id, function(val, key) {
+ self.increase_level(val, level + 1);
});
},
- edit_view : function(one_object){
+ edit_view: function(one_object) {
var self = this;
- this.dialog = new openerp.web.Dialog(this,{
+ this.edit_xml_dialog = new openerp.web.Dialog(this,{
modal: true,
title: 'Edit Xml',
width: 750,
@@ -283,135 +289,134 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
}
}
});
- this.dialog.start().open();
- this.dialog.$element.html(QWeb.render('view_editor', {
- 'data': one_object['main_object'],
- }));
- $("tr[id^='viewedit-']").click(function() {
- $("tr[id^='viewedit-']").removeClass('ui-selected');
- $(this).addClass('ui-selected');
- });
-
- $("img[id^='parentimg-']").click(function() {
- if ($(this).attr('src') == '/web/static/src/img/collapse.gif'){
- $(this).attr('src', '/web/static/src/img/expand.gif');
- self.on_expand(this);
- }else{
- $(this).attr('src', '/web/static/src/img/collapse.gif');
- var id = this.id.split('-')[1];
- self.on_collapse(this,one_object['parent_child_id'],one_object['main_object']);
- }
- });
- $("img[id^='side-']").click(function() {
- var side = $(this).closest("tr[id^='viewedit-']")
- var id_tr = (side.attr('id')).split('-')[1];
- var img = side.find("img[id='parentimg-"+id_tr+"']").attr('src'); ;
- var level = side.attr('level');
- var list_shift =[];
- var last_tr;
- var cur_tr = side;
- list_shift.push(side);
- var next_tr;
- switch (this.id)
- {
- case "side-add":
- break;
- case "side-remove":
- break;
- case "side-edit":
- var tag, fld_name;
- var tr = $(this).closest("tr[id^='viewedit-']").find('a').text();
- var tag_fld = tr.split(" ");
- if (tag_fld.length > 3){
- tag = tag_fld[1].replace(/[^a-zA-Z 0-9]+/g,'');
- fld_name = tag_fld[2].split("=")[1].replace(/[^a-zA-Z _ 0-9]+/g,'');
- }else{
- tag = tag_fld[1].replace(/[^a-zA-Z 0-9]+/g,'');
- }
- var properties = _PROPERTIES[tag];
- self.on_edit_node(properties,fld_name);
- break;
- case "side-up":
- while(1){
- var prev_tr = cur_tr.prev();
- if(level >= prev_tr.attr('level') || prev_tr.length==0){
- last_tr = prev_tr;
- break;
+ this.edit_xml_dialog.start().open();
+ this.edit_xml_dialog.$element.html(QWeb.render('view_editor', {
+ 'data': one_object['main_object'],
+ }));
+ this.edit_xml_dialog.$element.find("tr[id^='viewedit-']").click(function() {
+ $("tr[id^='viewedit-']").removeClass('ui-selected');
+ $(this).addClass('ui-selected');
+ });
+ this.edit_xml_dialog.$element.find("img[id^='parentimg-']").click(function() {
+ if ($(this).attr('src') == '/web/static/src/img/collapse.gif') {
+ $(this).attr('src', '/web/static/src/img/expand.gif');
+ self.on_expand(this);
+ } else {
+ $(this).attr('src', '/web/static/src/img/collapse.gif');
+ var id = this.id.split('-')[1];
+ self.on_collapse(this,one_object['parent_child_id'], one_object['main_object']);
+ }
+ });
+ this.edit_xml_dialog.$element.find("img[id^='side-']").click(function() {
+ var side = $(this).closest("tr[id^='viewedit-']")
+ var id_tr = (side.attr('id')).split('-')[1];
+ var img = side.find("img[id='parentimg-"+id_tr+"']").attr('src'); ;
+ var level = side.attr('level');
+ var list_shift =[];
+ var last_tr;
+ var cur_tr = side;
+ list_shift.push(side);
+ var next_tr;
+ switch (this.id) {
+ case "side-add":
+ break;
+ case "side-remove":
+ break;
+ case "side-edit":
+ var tag, fld_name;
+ var tr = $(this).closest("tr[id^='viewedit-']").find('a').text();
+ var tag_fld = tr.split(" ");
+ if (tag_fld.length > 3){
+ tag = tag_fld[1].replace(/[^a-zA-Z 0-9]+/g,'');
+ fld_name = tag_fld[2].split("=")[1].replace(/[^a-zA-Z _ 0-9]+/g,'');
+ }else{
+ tag = tag_fld[1].replace(/[^a-zA-Z 0-9]+/g,'');
}
- cur_tr = prev_tr;
- }
- if(img){
- while(1){
- next_tr = side.next();
- if(next_tr.attr('level') <= level || next_tr.length==0){
+ var properties = _PROPERTIES[tag];
+ self.on_edit_node(properties,fld_name);
+ break;
+ case "side-up":
+ while (1) {
+ var prev_tr = cur_tr.prev();
+ if(level >= prev_tr.attr('level') || prev_tr.length == 0) {
+ last_tr = prev_tr;
+ break;
+ }
+ cur_tr = prev_tr;
+ }
+ if (img) {
+ while (1) {
+ next_tr = side.next();
+ if (next_tr.attr('level') <= level || next_tr.length == 0) {
+ break;
+ } else {
+ list_shift.push(next_tr);
+ side = next_tr;
+ }
+ }
+ }
+ if (last_tr.length != 0 && last_tr.attr('level') == level) {
+ _.each(list_shift, function(rec) {
+ $(last_tr).before(rec);
+ });
+ }
+ break;
+ case "side-down":
+ if (img) {
+ while (1) {
+ next_tr = cur_tr.next();
+ if (next_tr.attr('level') <= level || next_tr.length == 0) {
+ last_tr = next_tr;
break;
- }else{
+ } else {
list_shift.push(next_tr);
- side = next_tr;
+ cur_tr = next_tr;
}
- }
+ }
}
- if(last_tr.length!=0 && last_tr.attr('level') == level){
- _.each(list_shift,function(rec){
- $(last_tr).before(rec);
- });
+ else {
+ last_tr = cur_tr.next();
}
- break;
- case "side-down":
- if(img){
- while(1){
- next_tr = cur_tr.next();
- if(next_tr.attr('level') <= level || next_tr.length==0){
- last_tr = next_tr;
- break;
- }else{
- list_shift.push(next_tr);
- cur_tr = next_tr;
- }
- }
- }
- else{
- last_tr = cur_tr.next();
- }
- if(last_tr.length != 0 && last_tr.attr('level')==level){
- var last_tr_id = (last_tr.attr('id')).split('-')[1];
- img = last_tr.find("img[id='parentimg-"+last_tr_id+"']").attr('src');
- if(img){
- $("img[id='parentimg-"+last_tr_id+"']").attr('src', '/web/static/src/img/expand.gif');
- while(1){
- var next_tr = last_tr.next();
- if (next_tr.attr('level') <= level || next_tr.length==0){break;}
- next_tr.hide();
- last_tr = next_tr;
+ if (last_tr.length != 0 && last_tr.attr('level') == level) {
+ var last_tr_id = (last_tr.attr('id')).split('-')[1];
+ img = last_tr.find("img[id='parentimg-" + last_tr_id + "']").attr('src');
+ if (img) {
+ this.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']").attr('src', '/web/static/src/img/expand.gif');
+ while (1) {
+ var next_tr = last_tr.next();
+ if (next_tr.attr('level') <= level || next_tr.length == 0) break;
+ next_tr.hide();
+ last_tr = next_tr;
+ }
}
+ list_shift.reverse();
+ _.each(list_shift, function(rec) {
+ $(last_tr).after(rec);
+ });
}
- list_shift.reverse();
- _.each(list_shift,function(rec){
- $(last_tr).after(rec);
- });
+ break;
}
- break;
- }
- });
+ });
},
- on_expand: function(self){
- var level = $(self).closest("tr[id^='viewedit-']").attr('level');
- var cur_tr = $(self).closest("tr[id^='viewedit-']");
- while (1){
+ on_expand: function(expand_img){
+ var level = parseInt($(expand_img).closest("tr[id^='viewedit-']").attr('level'));
+ var cur_tr = $(expand_img).closest("tr[id^='viewedit-']");
+ while (1) {
var nxt_tr = cur_tr.next();
- if (nxt_tr.attr('level') > level){
+ if (parseInt(nxt_tr.attr('level')) > level){
cur_tr = nxt_tr;
nxt_tr.hide();
- }else return nxt_tr;
+ } else return nxt_tr;
}
},
- on_collapse: function(self,parent_child_id,id,main_object){
- var id = self.id.split('-')[1];
- var datas = _.detect(parent_child_id,function(res){
+ on_collapse: function(collapse_img, parent_child_id, id, main_object) {
+ var self = this;
+ var id = collapse_img.id.split('-')[1];
+ var datas = _.detect(parent_child_id,function(res) {
return res.key == id;
});
- _.each(datas.value,function(rec){
- var tr = $("tr[id='viewedit-"+rec+"']");
+ _.each(datas.value, function(rec) {
+ var tr = self.edit_xml_dialog.$element.find("tr[id='viewedit-"+rec+"']");
tr.find("img[id='parentimg-"+rec+"']").attr('src','/web/static/src/img/expand.gif');
tr.show();
});
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index e184424fbd6..d55ecdbdc45 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -11,6 +11,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
*/
searchable: false,
form_template: "FormView",
+ identifier_prefix: 'formview-',
/**
* @constructs openerp.web.FormView
* @extends openerp.web.View
@@ -32,7 +33,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.widgets_counter = 0;
this.fields = {};
this.datarecord = {};
- this.ready = false;
this.show_invalid = true;
this.dirty_for_user = false;
this.default_focus_field = null;
@@ -43,6 +43,10 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.translatable_fields = [];
_.defaults(this.options, {"always_show_new_button": true,
"not_interactible_on_create": false});
+ this.mutating_lock = $.Deferred();
+ this.initial_mutating_lock = this.mutating_lock;
+ this.on_change_lock = $.Deferred().resolve();
+ this.reload_lock = $.Deferred().resolve();
},
start: function() {
this._super();
@@ -118,7 +122,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
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.attachments = new openerp.web.form.SidebarAttachments(this.sidebar, this);
this.sidebar.add_toolbar(this.fields_view.toolbar);
this.set_common_sidebar_sections(this.sidebar);
}
@@ -179,7 +183,8 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
}
this.on_form_changed();
- this.show_invalid = this.ready = true;
+ this.initial_mutating_lock.resolve();
+ this.show_invalid = true;
this.do_update_pager(record.id == null);
if (this.sidebar) {
this.sidebar.attachments.do_update();
@@ -222,69 +227,78 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
$pager.find('span.oe_pager_count').html(this.dataset.ids.length);
},
do_onchange: function(widget, processed) {
- processed = processed || [];
- if (widget.node.attrs.on_change) {
- var self = this;
- this.ready = false;
- var onchange = _.trim(widget.node.attrs.on_change);
- var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
- if (call) {
- var method = call[1], args = [];
- var context_index = null;
- var argument_replacement = {
- 'False' : function() {return false;},
- 'True' : function() {return true;},
- 'None' : function() {return null;},
- 'context': function(i) {
- context_index = i;
- var ctx = widget.build_context ? widget.build_context() : {};
- return ctx;
- }
- };
- var parent_fields = null;
- _.each(call[2].split(','), function(a, i) {
- var field = _.trim(a);
- if (field in argument_replacement) {
- args.push(argument_replacement[field](i));
- return;
- } else if (self.fields[field]) {
- var value = self.fields[field].get_on_change_value();
- args.push(value == null ? false : value);
- return;
- } else {
- var splitted = field.split('.');
- if (splitted.length > 1 && _.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
- if (parent_fields === null) {
- parent_fields = self.dataset.parent_view.get_fields_values();
- }
- var p_val = parent_fields[_.trim(splitted[1])];
- if (p_val !== undefined) {
- args.push(p_val == null ? false : p_val);
- return;
+ var self = this;
+ var act = function() {
+ try {
+ processed = processed || [];
+ if (widget.node.attrs.on_change) {
+ var onchange = _.trim(widget.node.attrs.on_change);
+ var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
+ if (call) {
+ var method = call[1], args = [];
+ var context_index = null;
+ var argument_replacement = {
+ 'False' : function() {return false;},
+ 'True' : function() {return true;},
+ 'None' : function() {return null;},
+ 'context': function(i) {
+ context_index = i;
+ var ctx = widget.build_context ? widget.build_context() : {};
+ return ctx;
+ }
+ };
+ var parent_fields = null;
+ _.each(call[2].split(','), function(a, i) {
+ var field = _.trim(a);
+ if (field in argument_replacement) {
+ args.push(argument_replacement[field](i));
+ return;
+ } else if (self.fields[field]) {
+ var value = self.fields[field].get_on_change_value();
+ args.push(value == null ? false : value);
+ return;
+ } else {
+ var splitted = field.split('.');
+ if (splitted.length > 1 && _.trim(splitted[0]) === "parent" && self.dataset.parent_view) {
+ if (parent_fields === null) {
+ parent_fields = self.dataset.parent_view.get_fields_values();
+ }
+ var p_val = parent_fields[_.trim(splitted[1])];
+ if (p_val !== undefined) {
+ args.push(p_val == null ? false : p_val);
+ return;
+ }
}
}
- }
- throw "Could not get field with name '" + field +
- "' for onchange '" + onchange + "'";
- });
- var ajax = {
- url: '/web/dataset/call',
- async: false
- };
- return this.rpc(ajax, {
- model: this.dataset.model,
- method: method,
- args: [(this.datarecord.id == null ? [] : [this.datarecord.id])].concat(args),
- context_id: context_index === null ? null : context_index + 1
- }, function(response) {
- self.on_processed_onchange(response, processed);
- });
- } else {
- console.log("Wrong on_change format", on_change);
+ throw "Could not get field with name '" + field +
+ "' for onchange '" + onchange + "'";
+ });
+ var ajax = {
+ url: '/web/dataset/call',
+ async: false
+ };
+ return self.rpc(ajax, {
+ model: self.dataset.model,
+ method: method,
+ args: [(self.datarecord.id == null ? [] : [self.datarecord.id])].concat(args),
+ context_id: context_index === null ? null : context_index + 1
+ }).pipe(function(response) {
+ return self.on_processed_onchange(response, processed);
+ });
+ } else {
+ console.log("Wrong on_change format", on_change);
+ }
}
- }
+ } catch(e) {
+ console.error(e);
+ return $.Deferred().reject();
+ }
+ };
+ this.on_change_lock = this.on_change_lock.pipe(act, act);
+ return this.on_change_lock;
},
on_processed_onchange: function(response, processed) {
+ try {
var result = response;
if (result.value) {
for (var f in result.value) {
@@ -317,7 +331,11 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (result.domain) {
// TODO:
}
- this.ready = true;
+ return $.Deferred().resolve();
+ } catch(e) {
+ console.error(e);
+ return $.Deferred().reject();
+ }
},
on_button_new: function() {
var self = this;
@@ -364,42 +382,50 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
*/
do_save: function(success, prepend_on_create) {
var self = this;
- if (!this.ready) {
- return $.Deferred().reject();
- }
- var form_dirty = false,
- form_invalid = false,
- values = {},
- first_invalid_field = null;
- for (var f in this.fields) {
- f = this.fields[f];
- if (!f.is_valid()) {
- form_invalid = true;
- f.update_dom();
- if (!first_invalid_field) {
- first_invalid_field = f;
+ var action = function() {
+ try {
+ if (!self.initial_mutating_lock.isResolved() && !self.initial_mutating_lock.isRejected())
+ return;
+ var form_dirty = false,
+ form_invalid = false,
+ values = {},
+ first_invalid_field = null;
+ for (var f in self.fields) {
+ f = self.fields[f];
+ if (!f.is_valid()) {
+ form_invalid = true;
+ f.update_dom();
+ if (!first_invalid_field) {
+ first_invalid_field = f;
+ }
+ } else if (f.is_dirty()) {
+ form_dirty = true;
+ values[f.name] = f.get_value();
}
- } else if (f.is_dirty()) {
- form_dirty = true;
- values[f.name] = f.get_value();
}
- }
- if (form_invalid) {
- first_invalid_field.focus();
- this.on_invalid();
- return $.Deferred().reject();
- } else {
- console.log("About to save", values);
- if (!this.datarecord.id) {
- return this.dataset.create(values).pipe(function(r) {
- return self.on_created(r, undefined, prepend_on_create);
- }).then(success);
+ if (form_invalid) {
+ first_invalid_field.focus();
+ self.on_invalid();
+ return $.Deferred().reject();
} else {
- return this.dataset.write(this.datarecord.id, values, {}).pipe(function(r) {
- return self.on_saved(r);
- }).then(success);
+ console.log("About to save", values);
+ if (!self.datarecord.id) {
+ return self.dataset.create(values).pipe(function(r) {
+ return self.on_created(r, undefined, prepend_on_create);
+ }).then(success);
+ } else {
+ return self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
+ return self.on_saved(r);
+ }).then(success);
+ }
}
- }
+ } catch (e) {
+ console.error(e);
+ return $.Deferred().reject();
+ }
+ };
+ this.mutating_lock = this.mutating_lock.pipe(action, action);
+ return this.mutating_lock;
},
do_save_edit: function() {
this.do_save();
@@ -417,7 +443,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
});
msg += "</ul>";
- this.notification.warn("The following fields are invalid :", msg);
+ this.do_warn("The following fields are invalid :", msg);
},
on_saved: function(r, success) {
if (!r.result) {
@@ -425,7 +451,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
return $.Deferred().reject();
} else {
this.reload();
- return $.Deferred().then(success).resolve(r);
+ return $.when(r).then(success);
}
},
/**
@@ -460,12 +486,9 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
console.debug("The record has been created with id #" + this.datarecord.id);
this.reload();
- return $.Deferred().then(success).resolve(_.extend(r, {created: true}));
+ return $.when(_.extend(r, {created: true})).then(success);
}
},
- do_search: function (domains, contexts, groupbys) {
- console.debug("Searching form");
- },
on_action: function (action) {
console.debug('Executing action', action);
},
@@ -473,11 +496,16 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
console.debug("Cancelling form");
},
reload: function() {
- if (this.dataset.index == null || this.dataset.index < 0) {
- this.on_button_new();
- } else {
- this.dataset.read_index(_.keys(this.fields_view.fields), this.on_record_loaded);
- }
+ var self = this;
+ var act = function() {
+ if (self.dataset.index == null || self.dataset.index < 0) {
+ return $.when(self.on_button_new());
+ } else {
+ return self.dataset.read_index(_.keys(self.fields_view.fields), self.on_record_loaded);
+ }
+ };
+ this.reload_lock = this.reload_lock.pipe(act, act);
+ return this.reload_lock;
},
get_fields_values: function() {
var values = {};
@@ -543,8 +571,12 @@ openerp.web.FormDialog = openerp.web.Dialog.extend({
openerp.web.form = {};
openerp.web.form.SidebarAttachments = openerp.web.Widget.extend({
- init: function(parent, element_id, form_view) {
- this._super(parent, element_id);
+ init: function(parent, form_view) {
+ var $section = parent.add_section(_t('Attachments'), 'attachments');
+ this.$div = $('<div class="oe-sidebar-attachments"></div>');
+ $section.append(this.$div);
+
+ this._super(parent, $section.attr('id'));
this.view = form_view;
},
do_update: function() {
@@ -562,7 +594,7 @@ openerp.web.form.SidebarAttachments = openerp.web.Widget.extend({
},
on_attachments_loaded: function(attachments) {
this.attachments = attachments;
- this.$element.html(QWeb.render('FormView.sidebar.attachments', this));
+ this.$div.html(QWeb.render('FormView.sidebar.attachments', this));
this.$element.find('.oe-binary-file').change(this.on_attachment_changed);
this.$element.find('.oe-sidebar-attachment-delete').click(this.on_attachment_delete);
},
@@ -584,7 +616,7 @@ openerp.web.form.SidebarAttachments = openerp.web.Widget.extend({
ids: [parseInt($e.attr('data-id'))]
}, function(r) {
$e.parent().remove();
- self.notification.notify("Delete an attachment", "The attachment '" + name + "' has been deleted");
+ self.do_notify("Delete an attachment", "The attachment '" + name + "' has been deleted");
});
}
}
@@ -688,7 +720,8 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.
this.width = this.node.attrs.width;
},
start: function() {
- this.$element = this.view.$element.find('.' + this.element_class);
+ this.$element = this.view.$element.find(
+ '.' + this.element_class.replace(/[^\r\n\f0-9A-Za-z_-]/g, "\\$&"));
},
process_modifiers: function() {
var compute_domain = openerp.web.form.compute_domain;
@@ -702,6 +735,51 @@ openerp.web.form.Widget = openerp.web.Widget.extend(/** @lends openerp.web.form.
render: function() {
var template = this.template;
return QWeb.render(template, { "widget": this });
+ },
+ _build_view_fields_values: function() {
+ var a_dataset = this.view.dataset;
+ var fields_values = this.view.get_fields_values();
+ var parent_values = a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {};
+ fields_values.parent = parent_values;
+ return fields_values;
+ },
+ _build_eval_context: function() {
+ var a_dataset = this.view.dataset;
+ return new openerp.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values());
+ },
+ /**
+ * Builds a new context usable for operations related to fields by merging
+ * the fields'context with the action's context.
+ */
+ build_context: function() {
+ var f_context = (this.field || {}).context || {};
+ if (!!f_context.__ref) {
+ var fields_values = this._build_eval_context();
+ f_context = new openerp.web.CompoundDomain(f_context).set_eval_context(fields_values);
+ }
+ // maybe the default_get should only be used when we do a default_get?
+ var v_contexts = _.compact([this.node.attrs.default_get || null,
+ this.node.attrs.context || null]);
+ var v_context = new openerp.web.CompoundContext();
+ _.each(v_contexts, function(x) {v_context.add(x);});
+ if (_.detect(v_contexts, function(x) {return !!x.__ref;})) {
+ var fields_values = this._build_eval_context();
+ v_context.set_eval_context(fields_values);
+ }
+ // if there is a context on the node, overrides the model's context
+ var ctx = v_contexts.length > 0 ? v_context : f_context;
+ return ctx;
+ },
+ build_domain: function() {
+ var f_domain = this.field.domain || [];
+ var n_domain = this.node.attrs.domain || null;
+ // if there is a domain on the node, overrides the model's domain
+ var final_domain = n_domain !== null ? n_domain : f_domain;
+ if (!(final_domain instanceof Array)) {
+ var fields_values = this._build_eval_context();
+ final_domain = new openerp.web.CompoundDomain(final_domain).set_eval_context(fields_values);
+ }
+ return final_domain;
}
});
@@ -757,6 +835,10 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({
var type = {};
if (node.tag == 'field') {
type = this.view.fields_view.fields[node.attrs.name] || {};
+ if (node.attrs.widget == 'statusbar') {
+ // This way we can retain backward compatibility between addons and old clients
+ node.attrs.nolabel = '1';
+ }
}
var widget = new (this.view.registry.get_any(
[node.attrs.widget, type.type, node.tag])) (this.view, node);
@@ -792,7 +874,7 @@ openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({
for (var i = 0; i < node.children.length; i++) {
var n = node.children[i];
if (n.tag == "page") {
- var page = new openerp.web.form.WidgetNotebookPage(
+ var page = new (this.view.registry.get_object('notebookpage'))(
this.view, n, this, this.pages.length);
this.pages.push(page);
}
@@ -811,7 +893,7 @@ openerp.web.form.WidgetNotebook = openerp.web.form.Widget.extend({
page.id = self.pages[index].element_id;
});
this.$element.tabs();
- this.view.on_button_new.add_last(this.do_select_first_visible_tab);
+ this.view.on_button_new.add_first(this.do_select_first_visible_tab);
},
do_select_first_visible_tab: function() {
for (var i = 0; i < this.pages.length; i++) {
@@ -898,11 +980,11 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({
self.on_confirmed().then(function() {
def.resolve();
});
- $(self).dialog("close");
+ $(this).dialog("close");
},
Cancel: function() {
def.resolve();
- $(self).dialog("close");
+ $(this).dialog("close");
}
}
});
@@ -911,7 +993,7 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({
return self.on_confirmed();
}
};
- if ((!this.node.attrs.special && this.view.dirty_for_user) || !this.view.datarecord.id) {
+ if (!this.node.attrs.special) {
return this.view.recursive_save().pipe(exec_action);
} else {
return exec_action();
@@ -920,8 +1002,15 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({
on_confirmed: function() {
var self = this;
+ var context = this.node.attrs.context;
+ if (context && context.__ref) {
+ context = new openerp.web.CompoundContext(context);
+ context.set_eval_context(this._build_eval_context());
+ }
+
return this.view.do_execute_action(
- this.node.attrs, this.view.dataset, this.view.datarecord.id, function () {
+ _.extend({}, this.node.attrs, {context: context}),
+ this.view.dataset, this.view.datarecord.id, function () {
self.view.reload();
});
},
@@ -1068,46 +1157,6 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
this.invalid = false;
},
focus: function() {
- },
- _build_view_fields_values: function() {
- var a_dataset = this.view.dataset;
- var fields_values = this.view.get_fields_values();
- var parent_values = a_dataset.parent_view ? a_dataset.parent_view.get_fields_values() : {};
- fields_values.parent = parent_values;
- return fields_values;
- },
- _build_eval_context: function() {
- var a_dataset = this.view.dataset;
- return new openerp.web.CompoundContext(a_dataset.get_context(), this._build_view_fields_values());
- },
- /**
- * Builds a new context usable for operations related to fields by merging
- * the fields'context with the action's context.
- */
- build_context: function() {
- var f_context = this.field.context || null;
- // maybe the default_get should only be used when we do a default_get?
- var v_contexts = _.compact([this.node.attrs.default_get || null,
- this.node.attrs.context || null]);
- var v_context = new openerp.web.CompoundContext();
- _.each(v_contexts, function(x) {v_context.add(x);});
- if (_.detect(v_contexts, function(x) {return !!x.__ref;})) {
- var fields_values = this._build_eval_context();
- v_context.set_eval_context(fields_values);
- }
- // if there is a context on the node, overrides the model's context
- var ctx = v_contexts.length > 0 ? v_context : f_context;
- return ctx;
- },
- build_domain: function() {
- var f_domain = this.field.domain || null;
- var v_domain = this.node.attrs.domain || [];
- if (!(v_domain instanceof Array) || true) { //TODO niv: remove || true
- var fields_values = this._build_eval_context();
- v_domain = new openerp.web.CompoundDomain(v_domain).set_eval_context(fields_values);
- }
- // if there is a domain on the node, overrides the model's domain
- return f_domain || v_domain;
}
});
@@ -1153,7 +1202,7 @@ openerp.web.form.FieldEmail = openerp.web.form.FieldChar.extend({
},
on_button_clicked: function() {
if (!this.value || !this.is_valid()) {
- this.notification.warn("E-mail error", "Can't send email to invalid e-mail address");
+ this.do_warn("E-mail error", "Can't send email to invalid e-mail address");
} else {
location.href = 'mailto:' + this.value;
}
@@ -1168,7 +1217,7 @@ openerp.web.form.FieldUrl = openerp.web.form.FieldChar.extend({
},
on_button_clicked: function() {
if (!this.value) {
- this.notification.warn("Resource error", "This resource is empty");
+ this.do_warn("Resource error", "This resource is empty");
} else {
window.open(this.value);
}
@@ -1787,6 +1836,9 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
result.result.context = _.extend(result.result.context || {}, additional_context);
self.do_action(result.result);
});
+ },
+ focus: function () {
+ this.$input.focus();
}
});
@@ -1842,6 +1894,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
this._super(view, node);
this.is_started = $.Deferred();
this.form_last_update = $.Deferred();
+ this.init_form_last_update = this.form_last_update;
this.disable_utility_classes = true;
},
start: function() {
@@ -1883,7 +1936,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
form: 'openerp.web.form.One2ManyFormView'
});
var once = $.Deferred().then(function() {
- self.form_last_update.resolve();
+ self.init_form_last_update.resolve();
});
this.viewmanager.on_controller_inited.add_last(function(view_type, controller) {
if (view_type == "list") {
@@ -1896,6 +1949,8 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
self.save_form_view();
});
controller.$element.find(".oe_form_button_save_edit").hide();
+ } else if (view_type == "graph") {
+ self.reload_current_view()
}
self.is_started.resolve();
});
@@ -1915,9 +1970,12 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
if (this.dataset.index === null && this.dataset.ids.length >= 1) {
this.dataset.index = 0;
}
- this.form_last_update.then(function() {
- this.form_last_update = view.do_show();
- });
+ var act = function() {
+ return view.do_show();
+ }
+ this.form_last_update = this.form_last_update.pipe(act, act);;
+ } else if (self.viewmanager.active_view === "graph") {
+ view.do_search(this.build_domain(), this.dataset.get_context(), []);
}
},
set_value: function(value) {
@@ -2006,9 +2064,10 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
var view = this.viewmanager.views[this.viewmanager.active_view].controller;
if (this.viewmanager.active_view === "form") {
var res = $.when(view.do_save());
- if (!res.isResolved() && !res.isRejected()) {
- throw "Asynchronous get_value() is not supported in form view.";
- }
+ // it seems line there are some cases when this happens
+ /*if (!res.isResolved() && !res.isRejected()) {
+ console.warn("Asynchronous get_value() is not supported in form view.");
+ }*/
return res;
}
}
@@ -2020,6 +2079,8 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
},
validate: function() {
this.invalid = false;
+ if (!this.viewmanager.views[this.viewmanager.active_view])
+ return;
var view = this.viewmanager.views[this.viewmanager.active_view].controller;
if (this.viewmanager.active_view === "form") {
for (var f in view.fields) {
@@ -2062,11 +2123,14 @@ openerp.web.form.One2ManyListView = openerp.web.ListView.extend({
pop.select_element(self.o2m.field.relation,{
initial_view: "form",
alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
- create_function: function(data) {
- return self.o2m.dataset.create(data, function(r) {
+ create_function: function(data, callback, error_callback) {
+ return self.o2m.dataset.create(data).then(function(r) {
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r.result]));
self.o2m.dataset.on_change();
- });
+ }).then(callback, error_callback);
+ },
+ read_function: function() {
+ return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments);
},
parent_view: self.o2m.view,
form_view_options: {'not_interactible_on_create':true}
@@ -2203,6 +2267,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
* - parent_view
* - form_view_options
* - list_view_options
+ * - read_function
*/
select_element: function(model, options, domain, context) {
var self = this;
@@ -2211,7 +2276,7 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
this.context = context || {};
this.options = _.defaults(options || {}, {"initial_view": "search", "create_function": function() {
return self.create_row.apply(self, arguments);
- }});
+ }, read_function: null});
this.initial_ids = this.options.initial_ids;
this.created_elements = [];
openerp.web.form.dialog(this.render(), {close:function() {
@@ -2221,8 +2286,18 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
},
start: function() {
this._super();
- this.dataset = new openerp.web.ReadOnlyDataSetSearch(this, this.model,
+ var self = this;
+ this.dataset = new openerp.web.ProxyDataSet(this, this.model,
this.context);
+ this.dataset.create_function = function() {
+ return self.options.create_function.apply(null, arguments).then(function(r) {
+ self.created_elements.push(r.result);
+ });
+ };
+ this.dataset.write_function = function() {
+ return self.write_row.apply(self, arguments);
+ };
+ this.dataset.read_function = this.options.read_function;
this.dataset.parent_view = this.options.parent_view;
this.dataset.on_default_get.add(this.on_default_get);
if (this.options.initial_view == "search") {
@@ -2243,11 +2318,11 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
});
this.searchview.on_search.add(function(domains, contexts, groupbys) {
if (self.initial_ids) {
- self.view_list.do_search.call(self, domains.concat([[["id", "in", self.initial_ids]], self.domain]),
+ self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]),
contexts, groupbys);
self.initial_ids = undefined;
} else {
- self.view_list.do_search.call(self, domains.concat([self.domain]), contexts, groupbys);
+ self.do_search(domains.concat([self.domain]), contexts, groupbys);
}
});
this.searchview.on_loaded.add_last(function () {
@@ -2274,15 +2349,30 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
}).pipe(function() {
self.searchview.do_search();
});
-
});
this.searchview.appendTo($("#" + this.element_id + "_search"));
},
- create_row: function(data) {
+ do_search: function(domains, contexts, groupbys) {
+ var self = this;
+ this.rpc('/web/session/eval_domain_and_context', {
+ domains: domains || [],
+ contexts: contexts || [],
+ group_by_seq: groupbys || []
+ }, function (results) {
+ self.view_list.do_search(results.domain, results.context, results.group_by);
+ });
+ },
+ create_row: function() {
+ var self = this;
+ var wdataset = new openerp.web.DataSetSearch(this, this.model, this.context, this.domain);
+ wdataset.parent_view = this.options.parent_view;
+ return wdataset.create.apply(wdataset, arguments);
+ },
+ write_row: function() {
var self = this;
var wdataset = new openerp.web.DataSetSearch(this, this.model, this.context, this.domain);
wdataset.parent_view = this.options.parent_view;
- return wdataset.create(data);
+ return wdataset.write.apply(wdataset, arguments);
},
on_select_elements: function(element_ids) {
},
@@ -2313,33 +2403,25 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
$buttons.html(QWeb.render("SelectCreatePopup.form.buttons", {widget:self}));
var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save-new");
$nbutton.click(function() {
- self._created = $.Deferred().then(function() {
- self._created = undefined;
- self.view_form.on_button_new();
+ $.when(self.view_form.do_save()).then(function() {
+ self.view_form.reload_lock.then(function() {
+ self.view_form.on_button_new();
+ });
});
- self.view_form.do_save();
});
var $nbutton = $buttons.find(".oe_selectcreatepopup-form-save");
$nbutton.click(function() {
- self._created = $.Deferred().then(function() {
- self._created = undefined;
- self.check_exit();
+ $.when(self.view_form.do_save()).then(function() {
+ self.view_form.reload_lock.then(function() {
+ self.check_exit();
+ });
});
- self.view_form.do_save();
});
var $cbutton = $buttons.find(".oe_selectcreatepopup-form-close");
$cbutton.click(function() {
self.check_exit();
});
});
- this.dataset.on_create.add(function(data) {
- self.options.create_function(data).then(function(r) {
- self.created_elements.push(r.result);
- if (self._created) {
- self._created.resolve();
- }
- });
- });
this.view_form.do_show();
},
check_exit: function() {
@@ -2401,7 +2483,6 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
this.setup_form_view();
},
on_write: function(id, data) {
- this.stop();
if (!this.options.auto_write)
return;
var self = this;
@@ -2424,7 +2505,9 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
$buttons.html(QWeb.render("FormOpenPopup.form.buttons"));
var $nbutton = $buttons.find(".oe_formopenpopup-form-save");
$nbutton.click(function() {
- self.view_form.do_save();
+ self.view_form.do_save().then(function() {
+ self.stop();
+ });
});
var $cbutton = $buttons.find(".oe_formopenpopup-form-close");
$cbutton.click(function() {
@@ -2436,7 +2519,7 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
}
});
-openerp.web.form.FormOpenDataset = openerp.web.ReadOnlyDataSetSearch.extend({
+openerp.web.form.FormOpenDataset = openerp.web.ProxyDataSet.extend({
read_ids: function() {
if (this.fop.options.read_function) {
return this.fop.options.read_function.apply(null, arguments);
@@ -2462,6 +2545,9 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({
};
this.get_fields_values = view.get_fields_values;
this.do_onchange = this.on_form_changed = this.on_nop;
+ this.dataset = this.view.dataset;
+ this.widgets_counter = 0;
+ this.view_id = 'reference_' + _.uniqueId();
this.widgets = {};
this.fields = {};
this.selection = new openerp.web.form.FieldSelection(this, { attrs: {
@@ -2477,8 +2563,10 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({
on_nop: function() {
},
on_selection_changed: function() {
- this.m2o.field.relation = this.selection.get_value();
+ var sel = this.selection.get_value();
+ this.m2o.field.relation = sel;
this.m2o.set_value(null);
+ this.m2o.$element.toggle(sel !== false);
},
start: function() {
this._super();
@@ -2522,10 +2610,6 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({
this.$element.find('button.oe-binary-file-save').click(this.on_save_as);
this.$element.find('.oe-binary-file-clear').click(this.on_clear);
},
- update_dom: function() {
- this._super.apply(this, arguments);
- this.$element.find('.oe-binary').toggle(!this.readonly);
- },
human_filesize : function(size) {
var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
var i = 0;
@@ -2543,29 +2627,28 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({
if ($(e.target).val() != '') {
this.$element.find('form.oe-binary-form input[name=session_id]').val(this.session.session_id);
this.$element.find('form.oe-binary-form').submit();
- this.toggle_progress();
+ this.$element.find('.oe-binary-progress').show();
+ this.$element.find('.oe-binary').hide();
}
},
- toggle_progress: function() {
- this.$element.find('.oe-binary-progress, .oe-binary').toggle();
- },
on_file_uploaded: function(size, name, content_type, file_base64) {
delete(window[this.iframe]);
if (size === false) {
- this.notification.warn("File Upload", "There was a problem while uploading your file");
+ this.do_warn("File Upload", "There was a problem while uploading your file");
// TODO: use openerp web crashmanager
console.warn("Error while uploading file : ", name);
} else {
this.on_file_uploaded_and_valid.apply(this, arguments);
this.on_ui_change();
}
- this.toggle_progress();
+ this.$element.find('.oe-binary-progress').hide();
+ this.$element.find('.oe-binary').show();
},
on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
},
on_save_as: function() {
if (!this.view.datarecord.id) {
- this.notification.warn("Can't save file", "The record has not yet been saved");
+ this.do_warn("Can't save file", "The record has not yet been saved");
} else {
var url = '/web/binary/saveas?session_id=' + this.session.session_id + '&model=' +
this.view.dataset.model +'&id=' + (this.view.datarecord.id || '') + '&field=' + this.name +
@@ -2585,6 +2668,10 @@ openerp.web.form.FieldBinary = openerp.web.form.Field.extend({
openerp.web.form.FieldBinaryFile = openerp.web.form.FieldBinary.extend({
template: 'FieldBinaryFile',
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('.oe-binary-file-set, .oe-binary-file-clear').toggle(!this.readonly);
+ },
set_value: function(value) {
this._super.apply(this, arguments);
var show_value = (value != null && value !== false) ? value : '';
@@ -2617,6 +2704,10 @@ openerp.web.form.FieldBinaryImage = openerp.web.form.FieldBinary.extend({
this._super.apply(this, arguments);
this.$image = this.$element.find('img.oe-binary-image');
},
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.$element.find('.oe-binary').toggle(!this.readonly);
+ },
set_value: function(value) {
this._super.apply(this, arguments);
this.set_image_maxwidth();
@@ -2781,6 +2872,7 @@ openerp.web.form.widgets = new openerp.web.Registry({
'frame' : 'openerp.web.form.WidgetFrame',
'group' : 'openerp.web.form.WidgetFrame',
'notebook' : 'openerp.web.form.WidgetNotebook',
+ 'notebookpage' : 'openerp.web.form.WidgetNotebookPage',
'separator' : 'openerp.web.form.WidgetSeparator',
'label' : 'openerp.web.form.WidgetLabel',
'button' : 'openerp.web.form.WidgetButton',
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 8a9deaab228..a97c249bfaf 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -391,9 +391,6 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
if (this.sidebar) {
this.sidebar.$element.show();
}
- if (!_(this.dataset.ids).isEmpty()) {
- this.reload_content();
- }
},
do_hide: function () {
this.$element.hide();
@@ -443,40 +440,21 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
}));
},
/**
- * Event handler for a search, asks for the computation/folding of domains
- * and contexts (and group-by), then reloads the view's content.
- *
- * @param {Array} domains a sequence of literal and non-literal domains
- * @param {Array} contexts a sequence of literal and non-literal contexts
- * @param {Array} groupbys a sequence of literal and non-literal group-by contexts
- * @returns {$.Deferred} fold request evaluation promise
- */
- do_search: function (domains, contexts, groupbys) {
- return this.rpc('/web/session/eval_domain_and_context', {
- domains: _([this.dataset.get_domain()].concat(domains)).compact(),
- contexts: _([this.dataset.get_context()].concat(contexts)).compact(),
- group_by_seq: groupbys
- }, $.proxy(this, 'do_actual_search'));
- },
- /**
* Handler for the result of eval_domain_and_context, actually perform the
* searching
*
* @param {Object} results results of evaluating domain and process for a search
*/
- do_actual_search: function (results) {
+ do_search: function (domain, context, group_by) {
this.groups.datagroup = new openerp.web.DataGroup(
- this, this.model,
- results.domain,
- results.context,
- results.group_by);
+ this, this.model, domain, context, group_by);
this.groups.datagroup.sort = this.dataset._sort;
- if (_.isEmpty(results.group_by) && !results.context['group_by_no_leaf']) {
- results.group_by = null;
+ if (_.isEmpty(group_by) && !context['group_by_no_leaf']) {
+ group_by = null;
}
- this.reload_view(!!results.group_by, results.context).then(
+ this.reload_view(!!group_by, context).then(
$.proxy(this, 'reload_content'));
},
/**
@@ -493,6 +471,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
_(ids).each(function (id) {
self.records.remove(self.records.get(id));
});
+ self.configure_pager(self.dataset);
self.compute_aggregates();
});
},
@@ -505,7 +484,13 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
do_select: function (ids, records) {
this.$element.find('.oe-list-delete')
.attr('disabled', !ids.length);
-
+ if (this.sidebar) {
+ if (ids.length) {
+ this.sidebar.do_unfold();
+ } else {
+ this.sidebar.do_fold();
+ }
+ }
if (!records.length) {
this.compute_aggregates();
return;
@@ -536,14 +521,8 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
* @param {openerp.web.DataSet} dataset dataset in which the record is available (may not be the listview's dataset in case of nested groups)
*/
do_activate_record: function (index, id, dataset) {
- var self = this;
- // TODO is it needed ?
- this.dataset.read_slice([],{
- context: dataset.get_context(),
- domain: dataset.get_domain()
- }, function () {
- self.select_record(index);
- });
+ this.dataset.ids = dataset.ids;
+ this.select_record(index);
},
/**
* Handles signal for the addition of a new record (can be a creation,
@@ -642,7 +621,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
}
$footer_cells.filter(_.sprintf('[data-field=%s]', column.id))
- .html(openerp.web.format_cell(aggregation, column));
+ .html(openerp.web.format_cell(aggregation, column, undefined, false));
});
},
get_selected_ids: function() {
@@ -806,6 +785,26 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
[this.records.at(this.dataset.index).get('id'),
this.dataset]);
},
+ render_cell: function (record, column) {
+ if (column.type === 'many2one') {
+ var value = record.get(column.id);
+ // m2o values are usually name_get formatted, [Number, String]
+ // pairs, but in some cases only the id is provided. In these
+ // cases, we need to perform a name_get call to fetch the actual
+ // displayable value
+ if (typeof value === 'number' || value instanceof Number) {
+ // fetch the name, set it on the record (in the right field)
+ // and let the various registered events handle refreshing the
+ // row
+ new openerp.web.DataSet(this.view, column.relation)
+ .name_get([value], function (names) {
+ if (!names.length) { return; }
+ record.set(column.id, names[0]);
+ });
+ }
+ }
+ return openerp.web.format_cell(record.toForm().data, column);
+ },
render: function () {
if (this.$current) {
this.$current.remove();
@@ -813,7 +812,7 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
this.$current = this.$_element.clone(true);
this.$current.empty().append(
QWeb.render('ListView.rows', _.extend({
- render_cell: openerp.web.format_cell}, this)));
+ render_cell: $.proxy(this, 'render_cell')}, this)));
this.pad_table_to(5);
},
pad_table_to: function (count) {
@@ -837,7 +836,9 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
cells.push('</tr>');
var row = cells.join('');
- this.$current.append(new Array(count - this.records.length + 1).join(row));
+ this.$current
+ .children('tr:not([data-id])').remove().end()
+ .append(new Array(count - this.records.length + 1).join(row));
this.refresh_zebra(this.records.length);
},
/**
@@ -918,7 +919,8 @@ openerp.web.ListView.List = openerp.web.Class.extend( /** @lends openerp.web.Lis
options: this.options,
record: record,
row_parity: (index % 2 === 0) ? 'even' : 'odd',
- render_cell: openerp.web.format_cell
+ view: this.view,
+ render_cell: $.proxy(this, 'render_cell')
});
},
/**
@@ -1169,7 +1171,8 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
var fields = _.pluck(_.select(this.columns, function(x) {return x.tag == "field"}), 'name');
var options = { offset: page * limit, limit: limit };
- dataset.read_slice(fields, options , function (records) {
+ //TODO xmo: investigate why we need to put the setTimeout
+ setTimeout(function() {dataset.read_slice(fields, options , function (records) {
if (!self.datagroup.openable) {
view.configure_pager(dataset);
} else {
@@ -1188,7 +1191,7 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
self.records.add(records, {silent: true});
list.render();
d.resolve(list);
- });
+ });}, 0);
return d.promise();
},
setup_resequence_rows: function (list, dataset) {
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index beb2c3ac0a9..4cc081a6266 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -22,6 +22,7 @@ openerp.web.list_editable = function (openerp) {
if (self.groups.get_selection().length) {
return;
}
+ self.configure_pager(self.dataset);
self.compute_aggregates();
}
})
@@ -56,11 +57,11 @@ openerp.web.list_editable = function (openerp) {
|| this.defaults.editable);
},
/**
- * Replace do_actual_search to handle editability process
+ * Replace do_search to handle editability process
*/
- do_actual_search: function (results) {
- this.set_editable(results.context['set_editable']);
- this._super(results);
+ do_search: function(domain, context, group_by) {
+ this.set_editable(context['set_editable']);
+ this._super.apply(this, arguments);
},
/**
* Replace do_add_record to handle editability (and adding new record
@@ -120,6 +121,7 @@ openerp.web.list_editable = function (openerp) {
delete self.edition_id;
delete self.edition;
});
+ this.pad_table_to(5);
return cancelled.promise();
},
/**
@@ -147,7 +149,7 @@ openerp.web.list_editable = function (openerp) {
var $new_row = $('<tr>', {
id: _.uniqueId('oe-editable-row-'),
'data-id': record_id,
- 'class': $(row).attr('class') + ' oe_forms',
+ 'class': row ? $(row).attr('class') : '' + ' oe_forms',
click: function (e) {e.stopPropagation();}
})
.delegate('button.oe-edit-row-save', 'click', function () {
@@ -173,14 +175,26 @@ openerp.web.list_editable = function (openerp) {
});
if (row) {
$new_row.replaceAll(row);
- } else if (self.options.editable === 'top') {
- self.$current.prepend($new_row);
} else if (self.options.editable) {
- self.$current.append($new_row);
+ var $last_child = self.$current.children('tr:last');
+ if (self.records.length) {
+ if (self.options.editable === 'top') {
+ $new_row.insertBefore(
+ self.$current.children('[data-id]:first'));
+ } else {
+ $new_row.insertAfter(
+ self.$current.children('[data-id]:last'));
+ }
+ } else {
+ $new_row.prependTo(self.$current);
+ }
+ if ($last_child.is(':not([data-id])')) {
+ $last_child.remove();
+ }
}
self.edition = true;
self.edition_id = record_id;
- self.edition_form = _.extend(new openerp.web.ListEditableFormView(self, self.dataset, false), {
+ self.edition_form = _.extend(new openerp.web.ListEditableFormView(self.view, self.dataset, false), {
form_template: 'ListView.row.form',
registry: openerp.web.list.form.widgets,
$element: $new_row
@@ -325,11 +339,13 @@ openerp.web.list_editable = function (openerp) {
this.$element.children().css('visibility', '');
if (this.modifiers.tree_invisible) {
var old_invisible = this.invisible;
- this.invisible = !!this.modifiers.tree_invisible;
+ this.invisible = true;
this._super();
this.invisible = old_invisible;
} else if (this.invisible) {
this.$element.children().css('visibility', 'hidden');
+ } else {
+ this._super();
}
}
});
diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js
index 7988d65805c..5143adb3838 100644
--- a/addons/web/static/src/js/view_tree.js
+++ b/addons/web/static/src/js/view_tree.js
@@ -32,6 +32,8 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
this.records = {};
this.options = _.extend({}, this.defaults, options || {});
+
+ _.bindAll(this, 'color_for');
},
start: function () {
@@ -107,6 +109,43 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
$select.change();
}
});
+
+ if (!this.fields_view.arch.attrs.colors) {
+ return;
+ }
+ this.colors = _(this.fields_view.arch.attrs.colors.split(';')).chain()
+ .compact()
+ .map(function(color_pair) {
+ var pair = color_pair.split(':'),
+ color = pair[0],
+ expr = pair[1];
+ return [color, py.parse(py.tokenize(expr)), expr];
+ }).value();
+ },
+ /**
+ * Returns the color for the provided record in the current view (from the
+ * ``@colors`` attribute)
+ *
+ * @param {Object} record record for the current row
+ * @returns {String} CSS color declaration
+ */
+ color_for: function (record) {
+ if (!this.colors) { return ''; }
+ var context = _.extend({}, record, {
+ uid: this.session.uid,
+ current_date: new Date().toString('yyyy-MM-dd')
+ // TODO: time, datetime, relativedelta
+ });
+ for(var i=0, len=this.colors.length; i<len; ++i) {
+ var pair = this.colors[i],
+ color = pair[0],
+ expression = pair[1];
+ if (py.evaluate(expression, context)) {
+ return 'color: ' + color + ';';
+ }
+ // TODO: handle evaluation errors
+ }
+ return '';
},
/**
* Sets up opening a row
@@ -159,7 +198,8 @@ openerp.web.TreeView = openerp.web.View.extend(/** @lends openerp.web.TreeView#
'fields_view': self.fields_view.arch.children,
'fields': self.fields,
'level': $curr_node.data('level') || 0,
- 'render': openerp.web.format_value
+ 'render': openerp.web.format_value,
+ 'color_for': self.color_for
});
if ($curr_node.length) {
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index be47cfc3364..703961e6238 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -68,9 +68,11 @@ db.web.ActionManager = db.web.Widget.extend({
},
on_url_hashchange: function(url) {
var self = this;
- self.rpc("/web/action/load", { action_id: url.action_id }, function(result) {
- self.do_action(result.result);
- });
+ if(url && url.action_id) {
+ self.rpc("/web/action/load", { action_id: url.action_id }, function(result) {
+ self.do_action(result.result);
+ });
+ }
},
do_action: function(action, on_close) {
var type = action.type.replace(/\./g,'_');
@@ -116,6 +118,15 @@ db.web.ActionManager = db.web.Widget.extend({
*/
},
ir_actions_act_window_close: function (action, on_closed) {
+ if (!this.dialog && on_closed) {
+ on_closed();
+ }
+ if (this.dialog && action.context) {
+ var model = action.context.active_model;
+ if (model === 'base.module.upgrade' || model === 'base.setup.installer' || model === 'base.module.upgrade') {
+ db.webclient.do_reload();
+ }
+ }
this.dialog_stop();
},
ir_actions_server: function (action, on_closed) {
@@ -166,6 +177,7 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
this.model = dataset ? dataset.model : undefined;
this.dataset = dataset;
this.searchview = null;
+ this.last_search = false;
this.active_view = null;
this.views_src = _.map(views, function(x) {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
this.views = {};
@@ -224,35 +236,21 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
controller.set_embedded_view(view.embedded_view);
}
controller.do_switch_view.add_last(this.on_mode_switch);
- if (view_type === 'list' && this.flags.search_view === false && this.action && this.action['auto_search']) {
- // In case the search view is not instantiated: manually call ListView#search
- var domains = !_(self.action.domain).isEmpty()
- ? [self.action.domain] : [],
- contexts = !_(self.action.context).isEmpty()
- ? [self.action.context] : [];
- controller.on_loaded.add({
- callback: function () {
- controller.do_search(domains, contexts, []);
- },
- position: 'last',
- unique: true
- });
- }
var container = $("#" + this.element_id + '_view_' + view_type);
view_promise = controller.appendTo(container);
+ this.views[view_type].controller = controller;
$.when(view_promise).then(function() {
self.on_controller_inited(view_type, controller);
+ if (self.searchview && view.controller.searchable !== false) {
+ self.do_searchview_search();
+ }
});
- this.views[view_type].controller = controller;
+ } else if (this.searchview && view.controller.searchable !== false) {
+ self.do_searchview_search();
}
-
if (this.searchview) {
- if (view.controller.searchable === false) {
- this.searchview.hide();
- } else {
- this.searchview.show();
- }
+ this.searchview[(view.controller.searchable === false || this.searchview.hidden) ? 'hide' : 'show']();
}
this.$element
@@ -273,14 +271,6 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
return view_promise;
},
/**
- * Event launched when a controller has been inited.
- *
- * @param {String} view_type type of view
- * @param {String} view the inited controller
- */
- on_controller_inited: function(view_type, view) {
- },
- /**
* Sets up the current viewmanager's search view.
*
* @param {Number|false} view_id the view to use or false for a default one
@@ -293,14 +283,37 @@ db.web.ViewManager = db.web.Widget.extend(/** @lends db.web.ViewManager# */{
}
this.searchview = new db.web.SearchView(
this, this.dataset,
- view_id, search_defaults);
+ view_id, search_defaults, this.flags.search_view === false);
- this.searchview.on_search.add(function(domains, contexts, groupbys) {
- var controller = self.views[self.active_view].controller;
- controller.do_search.call(controller, domains, contexts, groupbys);
- });
+ this.searchview.on_search.add(this.do_searchview_search);
return this.searchview.appendTo($("#" + this.element_id + "_search"));
},
+ do_searchview_search: function(domains, contexts, groupbys) {
+ var self = this,
+ controller = this.views[this.active_view].controller;
+ if (domains || contexts) {
+ this.rpc('/web/session/eval_domain_and_context', {
+ domains: [this.action.domain || []].concat(domains || []),
+ contexts: [this.action.context || {}].concat(contexts || []),
+ group_by_seq: groupbys || []
+ }, function (results) {
+ self.dataset.context = results.context;
+ self.dataset.domain = results.domain;
+ self.last_search = [results.domain, results.context, results.group_by];
+ controller.do_search(results.domain, results.context, results.group_by);
+ });
+ } else if (this.last_search) {
+ controller.do_search.apply(controller, this.last_search);
+ }
+ },
+ /**
+ * Event launched when a controller has been inited.
+ *
+ * @param {String} view_type type of view
+ * @param {String} view the inited controller
+ */
+ on_controller_inited: function(view_type, view) {
+ },
/**
* Called when one of the view want to execute an action
*/
@@ -360,28 +373,24 @@ db.web.ViewManagerAction = db.web.ViewManager.extend(/** @lends oepnerp.web.View
* launches an initial search after both views are done rendering.
*/
start: function() {
- var self = this;
+ var self = this,
+ searchview_loaded,
+ search_defaults = {};
+ _.each(this.action.context, function (value, key) {
+ var match = /^search_default_(.*)$/.exec(key);
+ if (match) {
+ search_defaults[match[1]] = value;
+ }
+ });
+ // init search view
+ var searchview_id = this.action['search_view_id'] && this.action['search_view_id'][0];
- var searchview_loaded;
- if (this.flags.search_view !== false) {
- var search_defaults = {};
- _.each(this.action.context, function (value, key) {
- var match = /^search_default_(.*)$/.exec(key);
- if (match) {
- search_defaults[match[1]] = value;
- }
- });
- // init search view
- var searchview_id = this.action['search_view_id'] && this.action['search_view_id'][0];
-
- searchview_loaded = this.setup_search_view(
- searchview_id || false, search_defaults);
- }
+ searchview_loaded = this.setup_search_view(searchview_id || false, search_defaults);
var main_view_loaded = this._super();
var manager_ready = $.when(searchview_loaded, main_view_loaded);
- if (searchview_loaded && this.action['auto_search']) {
+ if (searchview_loaded && this.action['auto_search'] !== false) {
// schedule auto_search
manager_ready.then(this.searchview.do_search);
}
@@ -511,9 +520,57 @@ db.web.Sidebar = db.web.Widget.extend({
self.do_toggle();
});
},
+
+ call_default_on_sidebar: function(item) {
+ var func_name = 'on_sidebar_' + _.underscored(item.label);
+ var fn = this.widget_parent[func_name];
+ if(typeof fn === 'function') {
+ fn(item);
+ }
+ },
+
+ add_default_sections: function() {
+ this.add_section(_t('Customize'), 'customize');
+ this.add_items('customize', [
+ {
+ label: _t("Manage Views"),
+ callback: this.call_default_on_sidebar,
+ title: _t("Manage views of the current object"),
+ }, {
+ label: _t("Edit Workflow"),
+ callback: this.call_default_on_sidebar,
+ title: _t("Manage views of the current object"),
+ classname: 'oe_hide oe_sidebar_edit_workflow'
+ }, {
+ label: _t("Customize Object"),
+ callback: this.call_default_on_sidebar,
+ title: _t("Manage views of the current object"),
+ }
+ ]);
+
+ this.add_section(_t('Other Options'), 'other');
+ this.add_items('other', [
+ {
+ label: _t("Import"),
+ callback: this.call_default_on_sidebar,
+ }, {
+ label: _t("Export"),
+ callback: this.call_default_on_sidebar,
+ }, {
+ label: _t("Translate"),
+ callback: this.call_default_on_sidebar,
+ classname: 'oe_sidebar_translate oe_hide'
+ }, {
+ label: _t("View Log"),
+ callback: this.call_default_on_sidebar,
+ classname: 'oe_hide oe_sidebar_view_log'
+ }
+ ]);
+ },
+
add_toolbar: function(toolbar) {
var self = this;
- _.each([['print', "Reports"], ['action', "Actions"], ['relate', "Links"]], function(type) {
+ _.each([['print', _t("Reports")], ['action', _t("Actions")], ['relate', _t("Links")]], function(type) {
var items = toolbar[type[0]];
if (items.length) {
for (var i = 0; i < items.length; i++) {
@@ -523,15 +580,30 @@ db.web.Sidebar = db.web.Widget.extend({
classname: 'oe_sidebar_' + type[0]
}
}
- self.add_section(type[0], type[1], items);
+ self.add_section(type[1], type[0]);
+ self.add_items(type[0], items);
}
});
},
- add_section: function(code, name, items) {
- // For each section, we pass a name/label and optionally an array of items.
- // If no items are passed, then the section will be created as a custom section
- // returning back an element_id to be used by a custom controller.
- // Else, the section is a standard section with items displayed as links.
+
+ add_section: function(name, code) {
+ if(!code) code = _.underscored(name);
+ var $section = this.sections[code];
+
+ if(!$section) {
+ section_id = _.uniqueId(this.element_id + '_section_' + code + '_');
+ var $section = $(db.web.qweb.render("Sidebar.section", {
+ section_id: section_id,
+ name: name,
+ classname: 'oe_sidebar_' + code,
+ }));
+ $section.appendTo(this.$element.find('div.sidebar-actions'));
+ this.sections[code] = $section;
+ }
+ return $section;
+ },
+
+ add_items: function(section_code, items) {
// An item is a dictonary : {
// label: label to be displayed for the link,
// action: action to be launch when the link is clicked,
@@ -540,25 +612,24 @@ db.web.Sidebar = db.web.Widget.extend({
// title: optional title for the link
// }
// Note: The item should have one action or/and a callback
+ //
+
var self = this,
- section_id = _.uniqueId(this.element_id + '_section_' + code + '_');
+ $section = this.add_section(_.titleize(section_code.replace('_', ' ')), section_code),
+ section_id = $section.attr('id');
+
if (items) {
for (var i = 0; i < items.length; i++) {
items[i].element_id = _.uniqueId(section_id + '_item_');
this.items[items[i].element_id] = items[i];
}
- }
- var $section = $(db.web.qweb.render("Sidebar.section", {
- section_id: section_id,
- name: name,
- classname: 'oe_sidebar_' + code,
- items: items
- }));
- if (items) {
- $section.find('a.oe_sidebar_action_a').click(function() {
+
+ var $items = $(db.web.qweb.render("Sidebar.section.items", {items: items}));
+
+ $items.find('a.oe_sidebar_action_a').click(function() {
var item = self.items[$(this).attr('id')];
if (item.callback) {
- item.callback();
+ item.callback.apply(self, [item]);
}
if (item.action) {
var ids = self.widget_parent.get_selected_ids();
@@ -588,10 +659,13 @@ db.web.Sidebar = db.web.Widget.extend({
}
return false;
});
+
+ var $ul = $section.find('ul');
+ if(!$ul.length) {
+ $ul = $('<ul/>').appendTo($section);
+ }
+ $items.appendTo($ul);
}
- $section.appendTo(this.$element.find('div.sidebar-actions'));
- this.sections[code] = $section;
- return section_id;
},
do_fold: function() {
this.$element.addClass('closed-sidebar').removeClass('open-sidebar');
@@ -770,7 +844,9 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
var self = this;
var result_handler = function () {
if (on_closed) { on_closed.apply(null, arguments); }
- return self.widget_parent.on_action_executed.apply(null, arguments);
+ if (self.widget_parent && self.widget_parent.on_action_executed) {
+ return self.widget_parent.on_action_executed.apply(null, arguments);
+ }
};
var handler = function (r) {
var action = r.result;
@@ -783,7 +859,8 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
}],
domains: []
}).pipe(function (results) {
- action.context = results.context
+ action.context = new db.web.CompoundContext(
+ results.context, action_data.context);
return self.do_action(action, result_handler);
});
} else {
@@ -816,47 +893,18 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
},
do_switch_view: function(view) {
},
+ do_search: function(view) {
+ },
+
set_common_sidebar_sections: function(sidebar) {
- sidebar.add_section('customize', "Customize", [
- {
- label: "Manage Views",
- callback: this.on_sidebar_manage_view,
- title: "Manage views of the current object"
- }, {
- label: "Edit Workflow",
- callback: this.on_sidebar_edit_workflow,
- title: "Manage views of the current object",
- classname: 'oe_hide oe_sidebar_edit_workflow'
- }, {
- label: "Customize Object",
- callback: this.on_sidebar_customize_object,
- title: "Manage views of the current object"
- }
- ]);
- sidebar.add_section('other', "Other Options", [
- {
- label: "Import",
- callback: this.on_sidebar_import
- }, {
- label: "Export",
- callback: this.on_sidebar_export
- }, {
- label: "Translate",
- callback: this.on_sidebar_translate,
- classname: 'oe_sidebar_translate oe_hide'
- }, {
- label: "View Log",
- callback: this.on_sidebar_view_log,
- classname: 'oe_hide oe_sidebar_view_log'
- }
- ]);
+ sidebar.add_default_sections();
},
- on_sidebar_manage_view: function() {
+ on_sidebar_manage_views: function() {
if (this.fields_view && this.fields_view.arch) {
var view_editor = new db.web.ViewEditor(this, this.$element, this.dataset, this.fields_view.arch);
view_editor.start();
} else {
- this.notification.warn("Manage Views", "Could not find current view declaration");
+ this.do_warn("Manage Views", "Could not find current view declaration");
}
},
on_sidebar_edit_workflow: function() {
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index b8da6dcab78..cc3a0af8341 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -2,9 +2,8 @@
<!-- vim:fdl=1:
-->
<templates id="template" xml:space="preserve">
-<t t-name="Interface">
- <div id="oe_loading" class="loading"></div>
- <div id="oe_notification" class="oe_notification">
+<t t-name="Notification">
+ <div class="oe_notification">
<div id="oe_notification_default">
<a class="ui-notify-cross ui-notify-close" href="#">x</a>
<h1>#{title}</h1>
@@ -17,6 +16,9 @@
<p>#{text}</p>
</div>
</div>
+</t>
+<t t-name="Interface">
+ <div id="oe_loading" class="loading"></div>
<table border="0" cellpadding="0" cellspacing="0" width="100%" height="100%" class="main_table">
<tr>
<td colspan="2" valign="top">
@@ -447,8 +449,8 @@
</blockquote>
<a class="oe-shortcut-toggle" title="Add / Remove Shortcut..."
href="javascript: void(0)"> </a>
- <h2 class="oe_view_title">
- <t t-esc="self.action.name"/>
+ <h2 class="oe_view_title" t-if="self.session.debug || self.flags.display_title !==false">
+ <t t-if="self.flags.display_title !==false" t-esc="self.action.name"/>
<button t-if="self.session.debug" class="oe_get_xml_view">
View#<span></span>
</button>
@@ -467,17 +469,20 @@
</div>
</t>
<t t-name="Sidebar.section">
- <h2><t t-esc="name"/></h2>
<div t-att-id="section_id" t-att-class="classname">
- <ul t-if="items">
+ <h2><t t-esc="name"/></h2>
+ </div>
+</t>
+
+
+<t t-name="Sidebar.section.items">
<li t-foreach="items" t-as="item" t-att-class="item.classname">
<a class="oe_sidebar_action_a" t-att-id="item.element_id" t-att-title="item.title" href="#">
<t t-esc="item.label"/>
</a>
</li>
- </ul>
- </div>
</t>
+
<t t-name="TranslateDialog">
<ul class="oe_translate_tabs">
<li><a t-attf-href="##{widget.element_id}_fields">Fields</a></li>
@@ -539,7 +544,7 @@
<td t-foreach="fields_view" t-as="field"
t-if="!field.attrs.modifiers.tree_invisible"
t-att-data-id="record.id"
- t-att-style="!field_index ? 'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px' : undefined"
+ t-att-style="color_for(record) + (!field_index ? 'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;' : '')"
t-att-class="!field_index and has_children ? 'treeview-tr' : 'treeview-td'">
<span t-if="!field.attrs.modifiers.invisible">
<t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" />
@@ -640,7 +645,7 @@
<td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help"
t-att-class="'oe-field-cell' + (align ? ' oe-number' : '')"
t-att-data-field="column.id">
- <t t-raw="render_cell(record.toForm().data, column)"/>
+ <t t-raw="render_cell(record, column)"/>
</td>
</t>
<td t-if="options.deletable" class='oe-record-delete' width="1">
@@ -776,7 +781,7 @@
<input type="text" size="12"
t-att-name="widget.name"
t-att-id="widget.element_id"
- t-attf-class="field_#{widget.type} #{widget.element_class}"
+ t-attf-class="field_#{widget.type}"
/>
<!-- img class="oe_field_translate" t-if="widget.field.translate" src="/web/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/-->
@@ -784,7 +789,7 @@
<t t-name="FieldChar.readonly">
<div
t-att-id="widget.element_id"
- t-attf-class="field_#{widget.type} #{widget.element_class}"
+ t-attf-class="field_#{widget.type}"
t-attf-style="width: #{widget.field.translate ? '99' : '100'}%">
</div>
</t>
@@ -823,7 +828,7 @@
<textarea rows="6"
t-att-name="widget.name"
t-att-id="widget.element_id"
- t-attf-class="field_#{widget.type} #{widget.element_class}"
+ t-attf-class="field_#{widget.type}"
t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
></textarea>
<img class="oe_field_translate" t-if="widget.field.translate" src="/web/static/src/img/icons/terp-translate.png" width="16" height="16" border="0"/>
@@ -842,8 +847,8 @@
<t t-name="FieldSelection">
<select
t-att-name="widget.name"
- t-att-id="widget.element_id + '_field'"
- t-attf-class="field_#{widget.type} #{widget.element_class}"
+ t-att-id="widget.element_id"
+ t-attf-class="field_#{widget.type}"
style="width: 100%">
<t t-foreach="widget.values" t-as="option">
<option><t t-esc="option[1]"/></option>
@@ -851,8 +856,9 @@
</select>
</t>
<t t-name="FieldMany2One">
- <div t-att-class="widget.element_class" class="oe-m2o">
- <input type="text" size="1" style="width: 100%;"/>
+ <div class="oe-m2o">
+ <input type="text" size="1" style="width: 100%;"
+ t-att-id="widget.element_id"/>
<span class="oe-m2o-drop-down-button">
<img src="/web/static/src/img/down-arrow.png" /></span>
<span class="oe-m2o-cm-button" t-att-id="widget.name + '_open'">
@@ -886,7 +892,7 @@
<td t-attf-class="oe_form_frame_cell oe_form_selection #{widget.selection.element_class}">
<t t-raw="widget.selection.render()"/>
</td>
- <td class="oe_form_frame_cell oe_form_many2one #{widget.selection.element_class}" nowrap="true">
+ <td t-attf-class="oe_form_frame_cell oe_form_many2one #{widget.m2o.element_class}" nowrap="true" style="display: none">
<t t-raw="widget.m2o.render()"/>
</td>
</tr>
@@ -895,8 +901,8 @@
<t t-name="FieldBoolean">
<input type="checkbox"
t-att-name="widget.name"
- t-att-id="widget.element_id + '_field'"
- t-attf-class="field_#{widget.type} #{widget.element_class}"/>
+ t-att-id="widget.element_id"
+ t-attf-class="field_#{widget.type}"/>
</t>
<t t-name="FieldProgressBar">
<div t-opentag="true" class="oe-progressbar">
@@ -911,7 +917,7 @@
t-att-border="widget.readonly ? 0 : 1"
t-att-id="widget.element_id + '_field'"
t-att-name="widget.name"
- t-attf-class="field_#{widget.type} #{widget.element_class}"
+ t-attf-class="field_#{widget.type}"
t-att-width="widget.node.attrs.img_width || widget.node.attrs.width"
t-att-height="widget.node.attrs.img_height || widget.node.attrs.height"
/>
@@ -959,7 +965,7 @@
<input type="text" size="1"
t-att-name="widget.name"
t-att-id="widget.element_id + '_field'"
- t-attf-class="field_#{widget.type} #{widget.element_class}" style="width: 100%"
+ t-attf-class="field_#{widget.type}" style="width: 100%"
/>
</td>
<td class="oe-binary" nowrap="true">
@@ -1004,7 +1010,6 @@
</t>
<t t-name="WidgetButton">
<button type="button"
- t-attf-class="#{widget.element_class}"
t-att-title="widget.help"
style="width: 100%" class="button">
<img t-if="widget.node.attrs.icon" t-att-src="'/web/static/src/img/icons/' + widget.node.attrs.icon + '.png'" width="16" height="16"/>
@@ -1101,14 +1106,14 @@
<div style="white-space: nowrap;">
<select t-att-name="attrs.name" t-att-id="element_id"
t-att-autofocus="attrs.default_focus === '1' || undefined">
- <option/>
+ <option t-if="prepend_empty"/>
<t t-foreach="attrs.selection" t-as="option">
<t t-set="selected" t-value="defaults[attrs.name] === option[0]"/>
<option t-if="selected"
- t-att-value="option[0]" selected="selected">
+ t-att-value="option_index" selected="selected">
<t t-esc="option[1]"/>
</option>
- <option t-if="!selected" t-att-value="option[0]">
+ <option t-if="!selected" t-att-value="option_index">
<t t-esc="option[1]"/>
</option>
</t>
@@ -1302,20 +1307,24 @@
<td align="left" class="view_editor" width="15%">
<table cellspacing="0" cellpadding ="0" width="100%">
<tr>
- <td>
- <img id="side-add" src="/web/static/src/img/icons/gtk-add.png" style="cursor: pointer;"/>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-add" src="/web/static/src/img/icons/gtk-add.png" style="cursor: pointer;"/>
</td>
- <td>
+ <td width="20%">
<img id="side-remove" src="/web/static/src/img/icons/gtk-remove.png" style="cursor: pointer;"/>
</td>
- <td>
- <img id="side-edit" src="/web/static/src/img/icons/gtk-edit.png" style="cursor: pointer;"/>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-edit" src="/web/static/src/img/icons/gtk-edit.png" style="cursor: pointer;"/>
</td>
- <td>
- <img id="side-up" src="/web/static/src/img/icons/gtk-go-up.png" style="cursor: pointer;"/>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-up" src="/web/static/src/img/icons/gtk-go-up.png" style="cursor: pointer;"/>
</td>
- <td>
- <img id="side-down" src="/web/static/src/img/icons/gtk-go-down.png" style="cursor: pointer;"/>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-down" src="/web/static/src/img/icons/gtk-go-down.png" style="cursor: pointer;"/>
</td>
</tr>
</table>
@@ -1570,4 +1579,4 @@
<t t-name="EmptyComponent">
<div></div>
</t>
-</templates>
+</templates> \ No newline at end of file