summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js
diff options
context:
space:
mode:
authorChristophe Simonis <chs@openerp.com>2011-09-26 13:26:23 +0200
committerChristophe Simonis <chs@openerp.com>2011-09-26 13:26:23 +0200
commit4261f1ad11fbe4772319190e59df80e504849bc4 (patch)
tree60c7b786c7851e12c1e92729450bf69554b449a5 /addons/web/static/src/js
parent01eff42ca26c312c75a1eee8d86a986a21c7d9a8 (diff)
parent47094e8adb39696638ecb7f4882812a47d0038e1 (diff)
merge upstream
bzr revid: chs@openerp.com-20110926112623-q68d3tebr80qt6l9
Diffstat (limited to 'addons/web/static/src/js')
-rw-r--r--addons/web/static/src/js/boot.js2
-rw-r--r--addons/web/static/src/js/chrome.js56
-rw-r--r--addons/web/static/src/js/core.js14
-rw-r--r--addons/web/static/src/js/data_import.js289
-rw-r--r--addons/web/static/src/js/formats.js12
-rw-r--r--addons/web/static/src/js/search.js38
-rw-r--r--addons/web/static/src/js/view_form.js111
-rw-r--r--addons/web/static/src/js/view_list.js8
-rw-r--r--addons/web/static/src/js/views.js2
9 files changed, 422 insertions, 110 deletions
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 27dc4dcda5e..447b6d92746 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -58,7 +58,7 @@ openerp.web = function(instance) {
openerp.web.formats(instance);
openerp.web.chrome(instance);
openerp.web.data(instance);
- var files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export"];
+ var files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export","data_import"];
for(var i=0; i<files.length; i++) {
if(openerp.web[files[i]]) {
openerp.web[files[i]](instance);
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index 8a8962fd27b..c6b065205d7 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -218,9 +218,8 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
this.$element.closest(".openerp")
.removeClass("login-mode")
.addClass("database_block");
-
+
var self = this;
-
var fetch_db = this.rpc("/web/database/get_list", {}, function(result) {
self.db_list = result.db_list;
});
@@ -232,7 +231,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.lang_list = result.lang_list;
});
$.when(fetch_db, fetch_langs).then(function () {self.do_create();});
-
+
this.$element.find('#db-create').click(this.do_create);
this.$element.find('#db-drop').click(this.do_drop);
this.$element.find('#db-backup').click(this.do_backup);
@@ -399,7 +398,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
do_restore: function() {
var self = this;
self.$option_id.html(QWeb.render("RestoreDB", self));
-
+
self.$option_id.find("form[name=restore_db_form]").validate({
submitHandler: function (form) {
$.blockUI({message:'<img src="/web/static/src/img/throbber2.gif">'});
@@ -467,10 +466,11 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
/**
* @constructs openerp.web.Login
* @extends openerp.web.Widget
- *
+ *
* @param parent
* @param element_id
*/
+
init: function(parent, element_id) {
this._super(parent, element_id);
this.has_local_storage = typeof(localStorage) != 'undefined';
@@ -496,7 +496,7 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
},
display: function() {
var self = this;
-
+
this.$element.html(QWeb.render("Login", this));
this.database = new openerp.web.Database(
this, "oe_database", "oe_db_options");
@@ -574,14 +574,13 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
/**
* @constructs openerp.web.Header
* @extends openerp.web.Widget
- *
+ *
* @param parent
*/
init: function(parent) {
this._super(parent);
this.qs = "?" + jQuery.param.querystring();
this.$content = $();
- console.debug("initializing header with id", this.element_id);
this.update_promise = $.Deferred().resolve();
},
start: function() {
@@ -666,7 +665,7 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
});
});
},
-
+
on_action: function(action) {
},
on_preferences: function(){
@@ -702,10 +701,11 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
},
Save: function(){
var inner_viewmanager = action_manager.inner_viewmanager;
- inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save(function(){
- inner_viewmanager.start();
+ inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save()
+ .then(function() {
+ self.dialog.stop();
+ window.location.reload();
});
- $(this).dialog('destroy')
}
}
});
@@ -713,7 +713,7 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
action_manager.appendTo(this.dialog);
action_manager.render(this.dialog);
},
-
+
change_password :function() {
var self = this;
this.dialog = new openerp.web.Dialog(this,{
@@ -728,21 +728,13 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
submitHandler: function (form) {
self.rpc("/web/session/change_password",{
'fields': $(form).serializeArray()
- }, function(result) {
- if (result.error) {
- self.display_error(result);
+ }, function(result) {
+ if (result.error) {
+ self.display_error(result);
return;
- }
- else {
- if (result.new_password) {
- self.session.password = result.new_password;
- var session = new openerp.web.Session(self.session.server, self.session.port);
- session.start();
- session.session_login(self.session.db, self.session.login, self.session.password)
- }
- }
- self.notification.notify("Changed Password", "Password has been changed successfully");
- self.dialog.close();
+ } else {
+ self.session.logout();
+ }
});
}
});
@@ -766,7 +758,7 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
/**
* @constructs openerp.web.Menu
* @extends openerp.web.Widget
- *
+ *
* @param parent
* @param element_id
* @param secondary_menu_id
@@ -918,7 +910,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
/**
* @constructs openerp.web.WebClient
* @extends openerp.web.Widget
- *
+ *
* @param element_id
*/
init: function(element_id) {
@@ -963,7 +955,6 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
this.session.start();
this.login.start();
this.menu.start();
- console.debug("The openerp client has been initialized.");
},
on_logged: function() {
if(this.action_manager)
@@ -1009,7 +1000,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
self.execute_home_action(home_action[0], ds);
})
},
- default_home: function () {
+ default_home: function () {
},
/**
* Bundles the execution of the home action
@@ -1034,7 +1025,6 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
},
do_url_set_hash: function(url) {
if(!this.url_external_hashchange) {
- console.log("url set #hash to",url);
this.url_internal_hashchange = true;
jQuery.bbq.pushState(url);
}
@@ -1042,10 +1032,8 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
on_url_hashchange: function() {
if(this.url_internal_hashchange) {
this.url_internal_hashchange = false;
- console.log("url jump to FLAG OFF");
} else {
var url = jQuery.deparam.fragment();
- console.log("url jump to",url);
this.url_external_hashchange = true;
this.action_manager.on_url_hashchange(url);
this.url_external_hashchange = false;
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index a33fca458d0..2e9294ded12 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -1,7 +1,10 @@
/*---------------------------------------------------------
* OpenERP Web core
*--------------------------------------------------------*/
-
+var console;
+if (!console) {
+ console = {log: function () {}};
+}
if (!console.debug) {
console.debug = console.log;
}
@@ -483,7 +486,8 @@ openerp.web.Session = openerp.web.CallbackEnabled.extend( /** @lends openerp.web
self.user_context = result.context;
self.db = result.db;
self.session_save();
- self.on_session_valid();
+ if (self.uid)
+ self.on_session_valid();
return true;
}).then(success_callback);
},
@@ -771,7 +775,6 @@ openerp.web.SessionAware = openerp.web.CallbackEnabled.extend(/** @lends openerp
* // stuff that you want to init before the rendering
* },
* start: function() {
- * this._super();
* // stuff you want to make after the rendering, `this.$element` holds a correct value
* this.$element.find(".my_button").click(/* an example of event binding * /);
*
@@ -915,6 +918,8 @@ openerp.web.Widget = openerp.web.SessionAware.extend(/** @lends openerp.web.Widg
* @returns {jQuery.Deferred}
*/
start: function() {
+ /* The default implementation is only useful for retro-compatibility, it is
+ not necessary to call it using _super() when using Widget for new components. */
if (!this.$element) {
var tmp = document.getElementById(this.element_id);
this.$element = tmp ? $(tmp) : undefined;
@@ -922,7 +927,7 @@ openerp.web.Widget = openerp.web.SessionAware.extend(/** @lends openerp.web.Widg
return $.Deferred().done().promise();
},
/**
- * Destroys the current widget, also destory all its children before destroying itself.
+ * Destroys the current widget, also destroy all its children before destroying itself.
*/
stop: function() {
_.each(_.clone(this.widget_children), function(el) {
@@ -943,7 +948,6 @@ openerp.web.Widget = openerp.web.SessionAware.extend(/** @lends openerp.web.Widg
* If that's not the case this method will simply return `false`.
*/
do_action: function(action, on_finished) {
- console.log('Widget.do_action', action, on_finished);
if (this.widget_parent) {
return this.widget_parent.do_action(action, on_finished);
}
diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js
new file mode 100644
index 00000000000..9c686846751
--- /dev/null
+++ b/addons/web/static/src/js/data_import.js
@@ -0,0 +1,289 @@
+openerp.web.data_import = function(openerp) {
+var QWeb = openerp.web.qweb;
+/**
+ * Safari does not deal well at all with raw JSON data being returned. As a
+ * result, we're going to cheat by using a pseudo-jsonp: instead of getting
+ * JSON data in the iframe, we're getting a ``script`` tag which consists of a
+ * function call and the returned data (the json dump).
+ *
+ * The function is an auto-generated name bound to ``window``, which calls
+ * back into the callback provided here.
+ *
+ * @param {Object} form the form element (DOM or jQuery) to use in the call
+ * @param {Object} attributes jquery.form attributes object
+ * @param {Function} callback function to call with the returned data
+ */
+function jsonp(form, attributes, callback) {
+ attributes = attributes || {};
+ var options = {jsonp: _.uniqueId('import_callback_')};
+ window[options.jsonp] = function () {
+ delete window[options.jsonp];
+ callback.apply(null, arguments);
+ };
+ if ('data' in attributes) {
+ _.extend(attributes.data, options);
+ } else {
+ _.extend(attributes, {data: options});
+ }
+ $(form).ajaxSubmit(attributes);
+}
+
+openerp.web.DataImport = openerp.web.Dialog.extend({
+ template: 'ImportDataView',
+ dialog_title: "Import Data",
+ init: function(parent, dataset){
+ var self = this;
+ this._super(parent, {});
+ this.model = parent.model;
+ this.fields = [];
+ this.all_fields = [];
+ this.required_fields = null;
+
+ var convert_fields = function (root, prefix) {
+ prefix = prefix || '';
+ _(root.fields).each(function (f) {
+ self.all_fields.push(prefix + f.name);
+ if (f.fields) {
+ convert_fields(f, prefix + f.id + '/');
+ }
+ });
+ };
+ this.ready = $.Deferred.queue().then(function () {
+ self.required_fields = _(self.fields).chain()
+ .filter(function (field) { return field.required; })
+ .pluck('name')
+ .value();
+ convert_fields(self);
+ self.all_fields.sort();
+ });
+ },
+ start: function() {
+ var self = this;
+ this._super();
+ this.open({
+ modal: true,
+ width: '70%',
+ height: 'auto',
+ position: 'top',
+ buttons: [
+ {text: "Close", click: function() { self.stop(); }},
+ {text: "Import File", click: function() { self.do_import(); }, 'class': 'oe-dialog-import-button'}
+ ],
+ close: function(event, ui) {
+ self.stop();
+ }
+ });
+ this.toggle_import_button(false);
+ this.$element.find('#csvfile').change(this.on_autodetect_data);
+ this.$element.find('fieldset').change(this.on_autodetect_data);
+ this.$element.find('fieldset legend').click(function() {
+ $(this).next().toggle();
+ });
+ this.ready.push(new openerp.web.DataSet(this, this.model).call(
+ 'fields_get', [], function (fields) {
+ self.graft_fields(fields);
+ }));
+ },
+ graft_fields: function (fields, parent, level) {
+ parent = parent || this;
+ level = level || 0;
+
+ var self = this;
+ _(fields).each(function (field, field_name) {
+ var f = {
+ id: field_name,
+ name: field_name,
+ string: field.string,
+ required: field.required
+ };
+
+ switch (field.type) {
+ case 'many2many':
+ case 'many2one':
+ f.name += '/id';
+ break;
+ case 'one2many':
+ f.name += '/id';
+ f.fields = [];
+ // only fetch sub-fields to a depth of 2 levels
+ if (level < 2) {
+ self.ready.push(new openerp.web.DataSet(self, field.relation).call(
+ 'fields_get', [], function (fields) {
+ self.graft_fields(fields, f, level+1);
+ }));
+ }
+ break;
+ }
+ parent.fields.push(f);
+ });
+ },
+ toggle_import_button: function (newstate) {
+ this.$dialog.dialog('widget')
+ .find('.oe-dialog-import-button')
+ .button('option', 'disabled', !newstate);
+ },
+ do_import: function() {
+ if(!this.$element.find('#csvfile').val()) { return; }
+ var lines_to_skip = parseInt(this.$element.find('#csv_skip').val(), 10);
+ var with_headers = this.$element.find('#file_has_headers').prop('checked');
+ if (!lines_to_skip && with_headers) {
+ lines_to_skip = 1;
+ }
+ var indices = [], fields = [];
+ this.$element.find(".sel_fields").each(function(index, element) {
+ var val = element.value;
+ if (!val) {
+ return;
+ }
+ indices.push(index);
+ fields.push(val);
+ });
+
+ jsonp(this.$element.find('#import_data'), {
+ url: '/web/import/import_data',
+ data: {
+ model: this.model,
+ meta: JSON.stringify({
+ skip: lines_to_skip,
+ indices: indices,
+ fields: fields
+ })
+ }
+ }, this.on_import_results);
+ },
+ on_autodetect_data: function() {
+ if(!this.$element.find('#csvfile').val()) { return; }
+ jsonp(this.$element.find('#import_data'), {
+ url: '/web/import/detect_data'
+ }, this.on_import_results);
+ },
+ on_import_results: function(results) {
+ this.$element.find('#result').empty();
+ var headers, result_node = this.$element.find("#result");
+
+ if (results['records']) {
+ var lines_to_skip = parseInt(this.$element.find('#csv_skip').val(), 10),
+ with_headers = this.$element.find('#file_has_headers').prop('checked');
+ headers = with_headers ? results.records[0] : null;
+
+ result_node.append(QWeb.render('ImportView.result', {
+ 'headers': headers,
+ 'records': lines_to_skip ? results.records.slice(lines_to_skip)
+ : with_headers ? results.records.slice(1)
+ : results.records
+ }));
+ } else if (results['error']) {
+ result_node.append(QWeb.render('ImportView.error', {
+ 'error': results['error']}));
+ } else if (results['success']) {
+ if (this.widget_parent.widget_parent.active_view == "list") {
+ this.widget_parent.reload_content();
+ }
+ this.stop();
+ return;
+ }
+
+ var self = this;
+ this.ready.then(function () {
+ var $fields = self.$element.find('.sel_fields').bind('blur', function () {
+ if (this.value && !_(self.all_fields).contains(this.value)) {
+ this.value = '';
+ }
+ }).autocomplete({
+ minLength: 0,
+ source: self.all_fields,
+ change: self.on_check_field_values
+ }).focus(function () {
+ $(this).autocomplete('search');
+ });
+ // Column auto-detection
+ _(headers).each(function (header, index) {
+ var f =_(self.fields).detect(function (field) {
+ // TODO: levenshtein between header and field.string
+ return field.name === header || field.string.toLowerCase() === header;
+ });
+ if (f) {
+ $fields.eq(index).val(f.name);
+ }
+ });
+ self.on_check_field_values();
+ });
+ },
+ /**
+ * Looks through all the field selections, and tries to find if two
+ * (or more) columns were matched to the same model field.
+ *
+ * Returns a map of the multiply-mapped fields to an array of offending
+ * columns (not actually columns, but the inputs containing the same field
+ * names).
+ *
+ * Also has the side-effect of marking the discovered inputs with the class
+ * ``duplicate_fld``.
+ *
+ * @returns {Object<String, Array<String>>} map of duplicate field matches to same-valued inputs
+ */
+ find_duplicate_fields: function() {
+ // Maps values to DOM nodes, in order to discover duplicates
+ var values = {}, duplicates = {};
+ this.$element.find(".sel_fields").each(function(index, element) {
+ var value = element.value;
+ var $element = $(element).removeClass('duplicate_fld');
+ if (!value) { return; }
+
+ if (!(value in values)) {
+ values[value] = element;
+ } else {
+ var same_valued_field = values[value];
+ if (value in duplicates) {
+ duplicates[value].push(element);
+ } else {
+ duplicates[value] = [same_valued_field, element];
+ }
+ $element.add(same_valued_field).addClass('duplicate_fld');
+ }
+ });
+ return duplicates;
+ },
+ on_check_field_values: function () {
+ this.$element.find("#message, #msg").remove();
+
+ var required_valid = this.check_required();
+
+ var duplicates = this.find_duplicate_fields();
+ if (_.isEmpty(duplicates)) {
+ this.toggle_import_button(required_valid);
+ } else {
+ var $err = $('<div id="msg" style="color: red;">Destination fields should only be selected once, some fields are selected more than once:</div>').insertBefore(this.$element.find('#result'));
+ var $dupes = $('<dl>').appendTo($err);
+ _(duplicates).each(function(elements, value) {
+ $('<dt>').text(value).appendTo($dupes);
+ _(elements).each(function(element) {
+ var cell = $(element).closest('td');
+ $('<dd>').text(cell.parent().children().index(cell)).appendTo($dupes);
+ });
+ });
+ this.toggle_import_button(false);
+ }
+
+ },
+ check_required: function() {
+ if (!this.required_fields.length) { return true; }
+
+ var selected_fields = _(this.$element.find('.sel_fields').get()).chain()
+ .pluck('value')
+ .compact()
+ .value();
+
+ var missing_fields = _.difference(this.required_fields, selected_fields);
+ if (missing_fields.length) {
+ this.$element.find("#result").before('<div id="message" style="color:red">*Required Fields are not selected : ' + missing_fields + '.</div>');
+ return false;
+ }
+ return true;
+ },
+ stop: function() {
+ $(this.$dialog).remove();
+ this._super();
+ }
+});
+};
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index 925490b7459..e7feedf26a5 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -118,26 +118,26 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) {
var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
Date.CultureInfo.formatPatterns.longTime));
if (tmp !== null)
- return tmp;
+ return openerp.web.datetime_to_str(tmp);
tmp = Date.parse(value);
if (tmp !== null)
- return tmp;
+ return openerp.web.datetime_to_str(tmp);
throw value + " is not a valid datetime";
case 'date':
var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.shortDate);
if (tmp !== null)
- return tmp;
+ return openerp.web.date_to_str(tmp);
tmp = Date.parse(value);
if (tmp !== null)
- return tmp;
+ return openerp.web.date_to_str(tmp);
throw value + " is not a valid date";
case 'time':
var tmp = Date.parseExact(value, Date.CultureInfo.formatPatterns.longTime);
if (tmp !== null)
- return tmp;
+ return openerp.web.time_to_str(tmp);
tmp = Date.parse(value);
if (tmp !== null)
- return tmp;
+ return openerp.web.time_to_str(tmp);
throw value + " is not a valid time";
}
return value;
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 94143d4bbfa..db91d6bfd27 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -795,20 +795,18 @@ openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @
* @extends openerp.web.search.DateField
*/
openerp.web.search.DateField = openerp.web.search.Field.extend(/** @lends openerp.web.search.DateField# */{
- /**
- * enables date picker on the HTML widgets
- */
+ template: "SearchView.date",
start: function () {
this._super();
- this.$element.addClass('field_date').datepicker({
- dateFormat: 'yy-mm-dd'
- });
- },
- stop: function () {
- this.$element.datepicker('destroy');
+ this.datewidget = new openerp.web.DateWidget(this);
+ this.datewidget.prependTo(this.$element);
+ this.datewidget.$element.find("input").attr("size", 15);
+ this.datewidget.$element.find("input").attr("autofocus",
+ this.attrs.default_focus === '1' ? 'autofocus' : undefined);
+ this.datewidget.set_value(this.defaults[this.attrs.name] || false);
},
get_value: function () {
- return this.$element.val();
+ return this.datewidget.get_value() || null;
}
});
/**
@@ -1123,7 +1121,7 @@ openerp.web.search.ExtendedSearchProposition.Char = openerp.web.OldWidget.extend
}
});
openerp.web.search.ExtendedSearchProposition.DateTime = openerp.web.OldWidget.extend({
- template: 'SearchView.extended_search.proposition.datetime',
+ template: 'SearchView.extended_search.proposition.empty',
identifier_prefix: 'extended-search-proposition-datetime',
operators: [
{value: "=", text: "is equal to"},
@@ -1134,18 +1132,16 @@ openerp.web.search.ExtendedSearchProposition.DateTime = openerp.web.OldWidget.ex
{value: "<=", text: "less or equal than"}
],
get_value: function() {
- return this.$element.val();
+ return this.datewidget.get_value();
},
start: function() {
this._super();
- this.$element.datetimepicker({
- dateFormat: 'yy-mm-dd',
- timeFormat: 'hh:mm:ss'
- });
+ this.datewidget = new openerp.web.DateTimeWidget(this);
+ this.datewidget.prependTo(this.$element);
}
});
openerp.web.search.ExtendedSearchProposition.Date = openerp.web.OldWidget.extend({
- template: 'SearchView.extended_search.proposition.date',
+ template: 'SearchView.extended_search.proposition.empty',
identifier_prefix: 'extended-search-proposition-date',
operators: [
{value: "=", text: "is equal to"},
@@ -1156,14 +1152,12 @@ openerp.web.search.ExtendedSearchProposition.Date = openerp.web.OldWidget.extend
{value: "<=", text: "less or equal than"}
],
get_value: function() {
- return this.$element.val();
+ return this.datewidget.get_value();
},
start: function() {
this._super();
- this.$element.datepicker({
- dateFormat: 'yy-mm-dd',
- timeFormat: 'hh:mm:ss'
- });
+ this.datewidget = new openerp.web.DateWidget(this);
+ this.datewidget.prependTo(this.$element);
}
});
openerp.web.search.ExtendedSearchProposition.Integer = openerp.web.OldWidget.extend({
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 31779648f3b..4b9432ca41a 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -1007,19 +1007,18 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
* the fields'context with the action's context.
*/
build_context: function() {
- // I previously belevied contexts should be herrited, but now I doubt it
- //var a_context = this.view.dataset.get_context() || {};
var f_context = this.field.context || null;
// maybe the default_get should only be used when we do a default_get?
- var v_context1 = this.node.attrs.default_get || {};
- var v_context2 = this.node.attrs.context || {};
- var v_context = new openerp.web.CompoundContext(v_context1, v_context2);
- if (v_context1.__ref || v_context2.__ref || true) { //TODO niv: remove || true
+ 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_view_fields_values();
v_context.set_eval_context(fields_values);
}
// if there is a context on the node, overrides the model's context
- var ctx = f_context || v_context;
+ var ctx = v_contexts.length > 0 ? v_context : f_context;
return ctx;
},
build_domain: function() {
@@ -1121,16 +1120,13 @@ openerp.web.form.FieldFloat = openerp.web.form.FieldChar.extend({
}
});
-openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
- init: function(view, node) {
- this._super(view, node);
- this.template = "FieldDate";
- this.jqueryui_object = 'datetimepicker';
- },
+openerp.web.DateTimeWidget = openerp.web.Widget.extend({
+ template: "web.datetimepicker",
+ jqueryui_object: 'datetimepicker',
+ type_of_date: "datetime",
start: function() {
var self = this;
- this._super.apply(this, arguments);
- this.$element.find('input').change(this.on_ui_change);
+ this.$element.find('input').change(this.on_change);
this.picker({
onSelect: this.on_picker_select,
changeMonth: true,
@@ -1148,6 +1144,8 @@ openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
this.$element.find('button.oe_datepicker_close').click(function() {
self.$element.find('.oe_datepicker').hide();
});
+ this.set_readonly(false);
+ this.value = false;
},
picker: function() {
return $.fn[this.jqueryui_object].apply(this.$element.find('.oe_datepicker_container'), arguments);
@@ -1157,63 +1155,96 @@ openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
this.$element.find('input').val(date ? this.format_client(date) : '').change();
},
set_value: function(value) {
- value = this.parse(value);
- this._super(value);
+ this.value = value;
this.$element.find('input').val(value ? this.format_client(value) : '');
},
get_value: function() {
- return this.format(this.value);
+ return this.value;
},
set_value_from_ui: function() {
var value = this.$element.find('input').val() || false;
this.value = this.parse_client(value);
- this._super();
},
- update_dom: function() {
- this._super.apply(this, arguments);
+ set_readonly: function(readonly) {
+ this.readonly = readonly;
this.$element.find('input').attr('disabled', this.readonly);
- this.$element.find('img.oe_datepicker_trigger').toggleClass('oe_input_icon_disabled', this.readonly);
+ this.$element.find('img.oe_datepicker_trigger').toggleClass('oe_input_icon_disabled', readonly);
},
- validate: function() {
- this.invalid = false;
+ is_valid: function(required) {
var value = this.$element.find('input').val();
if (value === "") {
- this.invalid = this.required;
+ return !required;
} else {
try {
this.parse_client(value);
- this.invalid = false;
+ return true;
} catch(e) {
- this.invalid = true;
+ return false;
}
}
},
focus: function() {
this.$element.find('input').focus();
},
- parse: openerp.web.auto_str_to_date,
parse_client: function(v) {
- return openerp.web.parse_value(v, this.field);
- },
- format: function(val) {
- return openerp.web.auto_date_to_str(val, this.field.type);
+ return openerp.web.parse_value(v, {"widget": this.type_of_date});
},
format_client: function(v) {
- return openerp.web.format_value(v, this.field);
+ return openerp.web.format_value(v, {"widget": this.type_of_date});
+ },
+ on_change: function() {
+ if (this.is_valid()) {
+ this.set_value_from_ui();
+ }
}
});
-openerp.web.form.FieldDate = openerp.web.form.FieldDatetime.extend({
- init: function(view, node) {
- this._super(view, node);
- this.jqueryui_object = 'datepicker';
- },
+openerp.web.DateWidget = openerp.web.DateTimeWidget.extend({
+ jqueryui_object: 'datepicker',
+ type_of_date: "date",
on_picker_select: function(text, instance) {
this._super(text, instance);
this.$element.find('.oe_datepicker').hide();
}
});
+openerp.web.form.FieldDatetime = openerp.web.form.Field.extend({
+ template: "EmptyComponent",
+ build_widget: function() {
+ return new openerp.web.DateTimeWidget(this);
+ },
+ start: function() {
+ var self = this;
+ this._super.apply(this, arguments);
+ this.datewidget = this.build_widget();
+ this.datewidget.on_change.add(this.on_ui_change);
+ this.datewidget.appendTo(this.$element);
+ },
+ set_value: function(value) {
+ this._super(value);
+ this.datewidget.set_value(value);
+ },
+ get_value: function() {
+ return this.datewidget.get_value();
+ },
+ update_dom: function() {
+ this._super.apply(this, arguments);
+ this.datewidget.set_readonly(this.readonly);
+ },
+ validate: function() {
+ this.invalid = !this.datewidget.is_valid(this.required);
+ },
+ focus: function() {
+ this.datewidget.focus();
+ }
+});
+
+openerp.web.form.FieldDate = openerp.web.form.FieldDatetime.extend({
+ build_widget: function() {
+ return new openerp.web.DateWidget(this);
+ }
+});
+
openerp.web.form.FieldText = openerp.web.form.Field.extend({
init: function(view, node) {
this._super(view, node);
@@ -1436,7 +1467,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
this.$input = this.$element.find("input");
this.$drop_down = this.$element.find(".oe-m2o-drop-down-button");
this.$menu_btn = this.$element.find(".oe-m2o-cm-button");
-
+
// context menu
var init_context_menu_def = $.Deferred().then(function(e) {
var rdataset = new openerp.web.DataSetStatic(self, "ir.values", self.build_context());
@@ -1444,7 +1475,7 @@ openerp.web.form.FieldMany2One = openerp.web.form.Field.extend({
[[self.field.relation, false]], false, rdataset.get_context()], false, 0)
.then(function(result) {
self.related_entries = result;
-
+
var $cmenu = $("#" + self.cm_id);
$cmenu.append(QWeb.render("FieldMany2One.context_menu", {widget: self}));
var bindings = {};
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index f8a89cd34a1..eeda44c4c99 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -415,8 +415,8 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
*/
do_search: function (domains, contexts, groupbys) {
return this.rpc('/web/session/eval_domain_and_context', {
- domains: [this.dataset.get_domain()].concat(domains),
- contexts: [this.dataset.get_context()].concat(contexts),
+ 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'));
},
@@ -541,6 +541,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
if (_.isEmpty(records)) {
records = this.groups.get_records();
}
+ records = _(records).compact();
var count = 0, sums = {};
_(columns).each(function (column) {
@@ -1235,6 +1236,9 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
},
get_records: function () {
if (_(this.children).isEmpty()) {
+ if (!this.datagroup.length) {
+ return;
+ }
return {
count: this.datagroup.length,
values: this.datagroup.aggregates
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 88db848118f..d31a3b05674 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -862,6 +862,8 @@ db.web.View = db.web.Widget.extend(/** @lends db.web.View# */{
console.log('Todo');
},
on_sidebar_import: function() {
+ var import_view = new db.web.DataImport(this, this.dataset);
+ import_view.start();
},
on_sidebar_export: function() {
var export_view = new db.web.DataExport(this, this.dataset);