diff options
| author | Christophe Simonis <chs@openerp.com> | 2011-09-26 13:26:23 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@openerp.com> | 2011-09-26 13:26:23 +0200 |
| commit | 4261f1ad11fbe4772319190e59df80e504849bc4 (patch) | |
| tree | 60c7b786c7851e12c1e92729450bf69554b449a5 /addons/web/static/src/js | |
| parent | 01eff42ca26c312c75a1eee8d86a986a21c7d9a8 (diff) | |
| parent | 47094e8adb39696638ecb7f4882812a47d0038e1 (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.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 56 | ||||
| -rw-r--r-- | addons/web/static/src/js/core.js | 14 | ||||
| -rw-r--r-- | addons/web/static/src/js/data_import.js | 289 | ||||
| -rw-r--r-- | addons/web/static/src/js/formats.js | 12 | ||||
| -rw-r--r-- | addons/web/static/src/js/search.js | 38 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 111 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 8 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 2 |
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); |
