'});
@@ -464,15 +463,19 @@ 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,
+
+ template: "Login",
+ identifier_prefix: 'oe-app-login-',
/**
* @constructs openerp.web.Login
* @extends openerp.web.Widget
- *
+ *
* @param parent
* @param element_id
*/
- init: function(parent, element_id) {
- this._super(parent, element_id);
+
+ init: function(parent) {
+ this._super(parent);
this.has_local_storage = typeof(localStorage) != 'undefined';
this.selected_db = null;
this.selected_login = null;
@@ -487,17 +490,6 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
},
start: function() {
var self = this;
- this.rpc("/web/database/get_list", {}, function(result) {
- self.db_list = result.db_list;
- self.display();
- }, function() {
- self.display();
- });
- },
- display: function() {
- var self = this;
-
- this.$element.html(QWeb.render("Login", this));
this.database = new openerp.web.Database(
this, "oe_database", "oe_db_options");
@@ -506,6 +498,17 @@ openerp.web.Login = openerp.web.Widget.extend(/** @lends openerp.web.Login# */{
});
this.$element.find("form").submit(this.on_submit);
+
+ this.rpc("/web/database/get_list", {}, function(result) {
+ var tpl = openerp.web.qweb.render('Login_dblist', {db_list: result.db_list, selected_db: self.selected_db});
+ self.$element.find("input[name=db]").replaceWith(tpl)
+ },
+ function(error, event) {
+ if (error.data.fault_code === 'AccessDenied') {
+ event.preventDefault();
+ }
+ });
+
},
on_login_invalid: function() {
this.$element.closest(".openerp").addClass("login-mode");
@@ -574,14 +577,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 +668,7 @@ openerp.web.Header = openerp.web.Widget.extend(/** @lends openerp.web.Header# *
});
});
},
-
+
on_action: function(action) {
},
on_preferences: function(){
@@ -702,10 +704,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 +716,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 +731,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 +761,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
@@ -776,74 +771,132 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
this.secondary_menu_id = secondary_menu_id;
this.$secondary_menu = $("#" + secondary_menu_id).hide();
this.menu = false;
+ this.folded = false;
+ if (window.localStorage) {
+ this.folded = localStorage.getItem('oe_menu_folded') === 'true';
+ }
+ this.float_timeout = 700;
},
start: function() {
+ this.$secondary_menu.addClass(this.folded ? 'oe_folded' : 'oe_unfolded');
+ this.reload();
+ },
+ reload: function() {
this.rpc("/web/menu/load", {}, this.on_loaded);
},
on_loaded: function(data) {
this.data = data;
- this.$element.html(QWeb.render("Menu", this.data));
- for (var i = 0; i < this.data.data.children.length; i++) {
- var v = { menu : this.data.data.children[i] };
- this.$secondary_menu.append(QWeb.render("Menu.secondary", v));
- }
- this.$secondary_menu.find("div.menu_accordion").accordion({
- animated : false,
- autoHeight : false,
- icons : false
- });
- this.$secondary_menu.find("div.submenu_accordion").accordion({
- animated : false,
- autoHeight : false,
- active: false,
- collapsible: true,
- header: 'h4'
- });
-
+ this.$element.html(QWeb.render("Menu", { widget : this }));
+ this.$secondary_menu.html(QWeb.render("Menu.secondary", { widget : this }));
this.$element.add(this.$secondary_menu).find("a").click(this.on_menu_click);
+ this.$secondary_menu.find('.oe_toggle_secondary_menu').click(this.on_toggle_fold);
+ },
+ on_toggle_fold: function() {
+ this.$secondary_menu.toggleClass('oe_folded').toggleClass('oe_unfolded');
+ if (this.folded) {
+ this.$secondary_menu.find('.oe_secondary_menu.active').show();
+ } else {
+ this.$secondary_menu.find('.oe_secondary_menu').hide();
+ }
+ this.folded = !this.folded;
+ if (window.localStorage) {
+ localStorage.setItem('oe_menu_folded', this.folded.toString());
+ }
},
on_menu_click: function(ev, id) {
id = id || 0;
- var $menu, $parent, $secondary;
+ var $clicked_menu, manual = false;
if (id) {
// We can manually activate a menu with it's id (for hash url mapping)
- $menu = this.$element.find('a[data-menu=' + id + ']');
- if (!$menu.length) {
- $menu = this.$secondary_menu.find('a[data-menu=' + id + ']');
+ manual = true;
+ $clicked_menu = this.$element.find('a[data-menu=' + id + ']');
+ if (!$clicked_menu.length) {
+ $clicked_menu = this.$secondary_menu.find('a[data-menu=' + id + ']');
}
} else {
- $menu = $(ev.currentTarget);
- id = $menu.data('menu');
- }
- if (this.$secondary_menu.has($menu).length) {
- $secondary = $menu.parents('.menu_accordion');
- $parent = this.$element.find('a[data-menu=' + $secondary.data('menu-parent') + ']');
- } else {
- $parent = $menu;
- $secondary = this.$secondary_menu.find('.menu_accordion[data-menu-parent=' + $menu.attr('data-menu') + ']');
+ $clicked_menu = $(ev.currentTarget);
+ id = $clicked_menu.data('menu');
}
- this.$secondary_menu.find('.menu_accordion').hide();
- // TODO: ui-accordion : collapse submenus and expand the good one
- $secondary.show();
-
- if (id) {
+ if (this.do_menu_click($clicked_menu, manual) && id) {
this.session.active_id = id;
- this.rpc('/web/menu/action', {'menu_id': id},
- this.on_menu_action_loaded);
+ this.rpc('/web/menu/action', {'menu_id': id}, this.on_menu_action_loaded);
}
+ ev.stopPropagation();
+ return false;
+ },
+ do_menu_click: function($clicked_menu, manual) {
+ var $sub_menu, $main_menu,
+ active = $clicked_menu.is('.active'),
+ sub_menu_visible = false;
+
+ if (this.$secondary_menu.has($clicked_menu).length) {
+ $sub_menu = $clicked_menu.parents('.oe_secondary_menu');
+ $main_menu = this.$element.find('a[data-menu=' + $sub_menu.data('menu-parent') + ']');
+ } else {
+ $sub_menu = this.$secondary_menu.find('.oe_secondary_menu[data-menu-parent=' + $clicked_menu.attr('data-menu') + ']');
+ $main_menu = $clicked_menu;
+ }
+
+ sub_menu_visible = $sub_menu.is(':visible');
+ this.$secondary_menu.find('.oe_secondary_menu').hide();
$('.active', this.$element.add(this.$secondary_menu.show())).removeClass('active');
- $parent.addClass('active');
- $menu.addClass('active');
- $menu.parent('h4').addClass('active');
+ $main_menu.add($clicked_menu).add($sub_menu).addClass('active');
- if (this.$secondary_menu.has($menu).length) {
- return !$menu.is(".leaf");
- } else {
- return false;
+ if (!(this.folded && manual)) {
+ this.do_show_secondary($sub_menu, $main_menu);
}
+
+ if ($main_menu != $clicked_menu) {
+ if ($clicked_menu.is('.submenu')) {
+ $sub_menu.find('.submenu.opened').each(function() {
+ if (!$(this).next().has($clicked_menu).length && !$(this).is($clicked_menu)) {
+ $(this).removeClass('opened').next().hide();
+ }
+ });
+ $clicked_menu.toggleClass('opened').next().toggle();
+ } else if ($clicked_menu.is('.leaf')) {
+ $sub_menu.toggle(!this.folded);
+ return true;
+ }
+ } else if (this.folded) {
+ if (active && sub_menu_visible) {
+ $sub_menu.hide();
+ return true;
+ }
+ } else {
+ return true;
+ }
+ return false;
+ },
+ do_show_secondary: function($sub_menu, $main_menu) {
+ var self = this;
+ if (this.folded) {
+ var css = $main_menu.position(),
+ fold_width = this.$secondary_menu.width() + 2,
+ window_width = $(window).width();
+ css.top += 33;
+ css.left -= Math.round(($sub_menu.width() - $main_menu.width()) / 2);
+ css.left = css.left < fold_width ? fold_width : css.left;
+ if ((css.left + $sub_menu.width()) > window_width) {
+ delete(css.left);
+ css.right = 1;
+ }
+ $sub_menu.css(css);
+ $sub_menu.mouseenter(function() {
+ clearTimeout($sub_menu.data('timeoutId'));
+ }).mouseleave(function(evt) {
+ var timeoutId = setTimeout(function() {
+ if (self.folded) {
+ $sub_menu.hide();
+ }
+ }, self.float_timeout);
+ $sub_menu.data('timeoutId', timeoutId);
+ });
+ }
+ $sub_menu.show();
},
on_menu_action_loaded: function(data) {
var self = this;
@@ -860,7 +913,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) {
@@ -883,7 +936,7 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
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, "oe_login");
+ this.login = new openerp.web.Login(this);
this.header.on_logout.add(this.login.on_logout);
this.header.on_action.add(this.on_menu_action);
@@ -903,9 +956,8 @@ openerp.web.WebClient = openerp.web.Widget.extend(/** @lends openerp.web.WebClie
start: function() {
this.header.appendTo($("#oe_header"));
this.session.start();
- this.login.start();
+ this.login.appendTo($('#oe_login'));
this.menu.start();
- console.debug("The openerp client has been initialized.");
},
on_logged: function() {
if(this.action_manager)
@@ -951,7 +1003,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
@@ -976,7 +1028,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);
}
@@ -984,10 +1035,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 dba47ee758c..9d4d2124008 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,6 @@ 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();
return true;
}).then(success_callback);
},
@@ -772,7 +774,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 * /);
*
@@ -916,6 +917,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;
@@ -923,7 +926,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) {
@@ -944,7 +947,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.js b/addons/web/static/src/js/data.js
index e5d323c8a96..fcf6a65dcf5 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -233,6 +233,7 @@ openerp.web.StaticDataGroup = openerp.web.GrouplessDataGroup.extend( /** @lends
});
openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet# */{
+ identifier_prefix: "dataset",
/**
* DateaManagement interface between views and the collection of selected
* OpenERP records (represents the view's state?)
@@ -242,16 +243,12 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
*
* @param {String} model the OpenERP model this dataset will manage
*/
- init: function(source_controller, model, context) {
- // we don't want the dataset to be a child of anything!
- this._super(null);
- this.session = source_controller ? source_controller.session : undefined;
+ init: function(parent, model, context) {
+ this._super(parent);
this.model = model;
this.context = context || {};
this.index = null;
},
- start: function() {
- },
previous: function () {
this.index -= 1;
if (this.index < 0) {
@@ -549,13 +546,11 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
sort: this.sort(),
offset: offset,
limit: options.limit || false
- }, function (result) {
+ }).pipe(function (result) {
self.ids = result.ids;
self.offset = offset;
- if (callback) {
- callback(result.records);
- }
- });
+ return result.records;
+ }).then(callback);
},
get_domain: function (other_domain) {
if (other_domain) {
@@ -603,20 +598,27 @@ openerp.web.DataSetSearch = openerp.web.DataSet.extend(/** @lends openerp.web.D
});
openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
virtual_id_prefix: "one2many_v_id_",
- virtual_id_regex: /one2many_v_id_.*/,
debug_mode: true,
init: function() {
this._super.apply(this, arguments);
this.reset_ids([]);
+ this.last_default_get = {};
+ },
+ default_get: function(fields, callback) {
+ return this._super(fields).then(this.on_default_get).then(callback);
+ },
+ on_default_get: function(res) {
+ this.last_default_get = res;
},
create: function(data, callback, error_callback) {
- var cached = {id:_.uniqueId(this.virtual_id_prefix), values: data};
+ 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 to_return = $.Deferred().then(callback);
- to_return.resolve({result: cached.id});
- return to_return.promise();
+ var prom = $.Deferred().then(callback);
+ setTimeout(function() {prom.resolve({result: cached.id});}, 0);
+ return prom.promise();
},
write: function (id, data, options, callback) {
var self = this;
@@ -676,7 +678,8 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
var cached = _.detect(self.cache, function(x) {return x.id === id;});
var created = _.detect(self.to_create, function(x) {return x.id === id;});
if (created) {
- _.each(fields, function(x) {if (cached.values[x] === undefined) cached.values[x] = false;});
+ _.each(fields, function(x) {if (cached.values[x] === undefined)
+ cached.values[x] = created.defaults[x] || false;});
} else {
if (!cached || !_.all(fields, function(x) {return cached.values[x] !== undefined}))
to_get.push(id);
@@ -715,7 +718,13 @@ openerp.web.BufferedDataSet = openerp.web.DataSetStatic.extend({
return completion.promise();
}
});
+openerp.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
+
openerp.web.ReadOnlyDataSetSearch = openerp.web.DataSetSearch.extend({
+ 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);
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| + | +
+
+
+ |
+