[REM] import from core, moving to module
bzr revid: xmo@openerp.com-20120911063607-xvhyjqohptynro30
This commit is contained in:
parent
063c548209
commit
5848e72d42
|
@ -48,7 +48,6 @@ This module provides the core of the OpenERP Web Client.
|
||||||
"static/src/js/views.js",
|
"static/src/js/views.js",
|
||||||
"static/src/js/data.js",
|
"static/src/js/data.js",
|
||||||
"static/src/js/data_export.js",
|
"static/src/js/data_export.js",
|
||||||
"static/src/js/data_import.js",
|
|
||||||
"static/src/js/search.js",
|
"static/src/js/search.js",
|
||||||
"static/src/js/view_form.js",
|
"static/src/js/view_form.js",
|
||||||
"static/src/js/view_list.js",
|
"static/src/js/view_list.js",
|
||||||
|
@ -63,7 +62,6 @@ This module provides the core of the OpenERP Web Client.
|
||||||
"static/lib/jquery.textext/jquery.textext.css",
|
"static/lib/jquery.textext/jquery.textext.css",
|
||||||
"static/src/css/base.css",
|
"static/src/css/base.css",
|
||||||
"static/src/css/data_export.css",
|
"static/src/css/data_export.css",
|
||||||
"static/src/css/data_import.css",
|
|
||||||
"static/lib/cleditor/jquery.cleditor.css",
|
"static/lib/cleditor/jquery.cleditor.css",
|
||||||
],
|
],
|
||||||
'qweb' : [
|
'qweb' : [
|
||||||
|
|
|
@ -2574,10 +2574,13 @@
|
||||||
.openerp .oe_form .oe_form_field_many2many > .oe_list .oe_list_pager_single_page {
|
.openerp .oe_form .oe_form_field_many2many > .oe_list .oe_list_pager_single_page {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.openerp .oe_list_buttons .oe_alternative {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
.openerp .oe_list_buttons .oe_list_save, .openerp .oe_list_buttons .oe_list_discard {
|
.openerp .oe_list_buttons .oe_list_save, .openerp .oe_list_buttons .oe_list_discard {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.openerp .oe_list_buttons.oe_editing .oe_list_add, .openerp .oe_list_buttons.oe_editing .oe_list_button_import {
|
.openerp .oe_list_buttons.oe_editing .oe_list_add {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.openerp .oe_list_buttons.oe_editing .oe_list_save {
|
.openerp .oe_list_buttons.oe_editing .oe_list_save {
|
||||||
|
@ -2586,6 +2589,9 @@
|
||||||
.openerp .oe_list_buttons.oe_editing .oe_list_discard {
|
.openerp .oe_list_buttons.oe_editing .oe_list_discard {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
.openerp .oe_list_buttons.oe_editing .oe_alternative {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
.openerp .oe_list {
|
.openerp .oe_list {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1971,15 +1971,19 @@ $sheet-max-width: 860px
|
||||||
// }}}
|
// }}}
|
||||||
// ListView {{{
|
// ListView {{{
|
||||||
.oe_list_buttons
|
.oe_list_buttons
|
||||||
|
.oe_alternative
|
||||||
|
visibility: hidden
|
||||||
.oe_list_save, .oe_list_discard
|
.oe_list_save, .oe_list_discard
|
||||||
display: none
|
display: none
|
||||||
&.oe_editing
|
&.oe_editing
|
||||||
.oe_list_add, .oe_list_button_import
|
.oe_list_add
|
||||||
display: none
|
display: none
|
||||||
.oe_list_save
|
.oe_list_save
|
||||||
display: inline-block
|
display: inline-block
|
||||||
.oe_list_discard
|
.oe_list_discard
|
||||||
display: inline
|
display: inline
|
||||||
|
.oe_alternative
|
||||||
|
visibility: visible
|
||||||
|
|
||||||
.oe_list
|
.oe_list
|
||||||
position: relative
|
position: relative
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
.openerp .oe_import_grid {
|
|
||||||
border: none;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
.openerp .oe_import_grid-header .oe_import_grid-cell {
|
|
||||||
background: url(../img/gradientlinebg.gif) repeat-x #CCCCCC;
|
|
||||||
border-bottom: 1px solid #E3E3E3;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.openerp .oe_import_grid-row .oe_import_grid-cell {
|
|
||||||
border-bottom: 1px solid #E3E3E3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openerp .oe_import_no_result .oe_import_result {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.openerp .oe_import fieldset {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.openerp .oe_import fieldset legend:before {
|
|
||||||
content: '\25BC ';
|
|
||||||
}
|
|
||||||
.openerp .oe_import fieldset.oe_closed legend:before {
|
|
||||||
content: '\25B6 ';
|
|
||||||
}
|
|
||||||
.openerp .oe_import fieldset.oe_closed table {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.openerp .oe_import .separator.horizontal {
|
|
||||||
font-weight: bold;
|
|
||||||
border-bottom-width: 1px;
|
|
||||||
margin: 6px 4px 6px 1px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
.openerp .duplicate_fld{
|
|
||||||
background-color:#FF6666;
|
|
||||||
}
|
|
||||||
.openerp .select_fld{
|
|
||||||
background: none repeat scroll 0 0 white;
|
|
||||||
}
|
|
||||||
.openerp .ui-autocomplete {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
|
@ -1,393 +0,0 @@
|
||||||
openerp.web.data_import = function(instance) {
|
|
||||||
var QWeb = instance.web.qweb,
|
|
||||||
_t = instance.web._t;
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
instance.web.DataImport = instance.web.Dialog.extend({
|
|
||||||
template: 'ImportDataView',
|
|
||||||
dialog_title: {toString: function () { return _t("Import Data"); }},
|
|
||||||
init: function(parent, dataset){
|
|
||||||
var self = this;
|
|
||||||
this._super(parent, {});
|
|
||||||
this.model = parent.model;
|
|
||||||
this.fields = [];
|
|
||||||
this.all_fields = [];
|
|
||||||
this.fields_with_defaults = [];
|
|
||||||
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 &&
|
|
||||||
!_.include(self.fields_with_defaults, field.id); })
|
|
||||||
.pluck('id')
|
|
||||||
.uniq()
|
|
||||||
.value();
|
|
||||||
convert_fields(self);
|
|
||||||
self.all_fields.sort();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
start: function() {
|
|
||||||
var self = this;
|
|
||||||
this._super();
|
|
||||||
this.open({
|
|
||||||
buttons: [
|
|
||||||
{text: _t("Close"), click: function() { self.destroy(); }},
|
|
||||||
{text: _t("Import File"), click: function() { self.do_import(); }, 'class': 'oe_import_dialog_button'}
|
|
||||||
],
|
|
||||||
close: function(event, ui) {
|
|
||||||
self.destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.toggle_import_button(false);
|
|
||||||
this.$el.find('#csvfile').change(this.on_autodetect_data);
|
|
||||||
this.$el.find('fieldset').change(this.on_autodetect_data);
|
|
||||||
this.$el.delegate('fieldset legend', 'click', function() {
|
|
||||||
$(this).parent().toggleClass('oe_closed');
|
|
||||||
});
|
|
||||||
this.ready.push(new instance.web.DataSet(this, this.model).call(
|
|
||||||
'fields_get', [], function (fields) {
|
|
||||||
self.graft_fields(fields);
|
|
||||||
self.ready.push(new instance.web.DataSet(self, self.model)
|
|
||||||
.default_get(_.pluck(self.fields, 'id')).then(function (fields) {
|
|
||||||
_.each(fields, function(val, key) {
|
|
||||||
if (val) {
|
|
||||||
self.fields_with_defaults.push(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
graft_fields: function (fields, parent, level) {
|
|
||||||
parent = parent || this;
|
|
||||||
level = level || 0;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
if (level === 0) {
|
|
||||||
parent.fields.push({
|
|
||||||
id: 'id',
|
|
||||||
name: 'id',
|
|
||||||
string: _t('External ID'),
|
|
||||||
required: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_(fields).each(function (field, field_name) {
|
|
||||||
// Ignore spec for id field
|
|
||||||
// Don't import function fields (function and related)
|
|
||||||
if (field_name === 'id') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Skip if there's no state which could disable @readonly,
|
|
||||||
// if a field is ever always readonly we can't import it
|
|
||||||
if (field.readonly) {
|
|
||||||
// no states at all
|
|
||||||
if (_.isEmpty(field.states)) { return; }
|
|
||||||
// no state altering @readonly
|
|
||||||
if (!_.any(field.states, function (modifiers) {
|
|
||||||
return _(modifiers).chain().pluck(0).contains('readonly').value();
|
|
||||||
})) { return; }
|
|
||||||
}
|
|
||||||
|
|
||||||
var f = {
|
|
||||||
id: field_name,
|
|
||||||
name: field_name,
|
|
||||||
string: field.string,
|
|
||||||
required: field.required
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (field.type) {
|
|
||||||
case 'many2many':
|
|
||||||
case 'many2one':
|
|
||||||
// push a copy for the bare many2one field, to allow importing
|
|
||||||
// using name_search too - even if we default to exporting the XML ID
|
|
||||||
var many2one_field = _.extend({}, f)
|
|
||||||
parent.fields.push(many2one_field);
|
|
||||||
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 instance.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) {
|
|
||||||
instance.web.dialog(this.$el, 'widget')
|
|
||||||
.find('.oe_import_dialog_button')
|
|
||||||
.button('option', 'disabled', !newstate);
|
|
||||||
},
|
|
||||||
do_import: function() {
|
|
||||||
if(!this.$el.find('#csvfile').val()) { return; }
|
|
||||||
var lines_to_skip = parseInt(this.$el.find('#csv_skip').val(), 10);
|
|
||||||
var with_headers = this.$el.find('#file_has_headers').prop('checked');
|
|
||||||
if (!lines_to_skip && with_headers) {
|
|
||||||
lines_to_skip = 1;
|
|
||||||
}
|
|
||||||
var indices = [], fields = [];
|
|
||||||
this.$el.find(".sel_fields").each(function(index, element) {
|
|
||||||
var val = element.value;
|
|
||||||
if (!val) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
indices.push(index);
|
|
||||||
fields.push(val);
|
|
||||||
});
|
|
||||||
|
|
||||||
jsonp(this.$el.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.$el.find('#csvfile').val()) { return; }
|
|
||||||
jsonp(this.$el.find('#import_data'), {
|
|
||||||
url: '/web/import/detect_data'
|
|
||||||
}, this.on_import_results);
|
|
||||||
},
|
|
||||||
on_import_results: function(results) {
|
|
||||||
this.$el.find('#result').empty();
|
|
||||||
var headers, result_node = this.$el.find("#result");
|
|
||||||
|
|
||||||
if (results['error']) {
|
|
||||||
result_node.append(QWeb.render('ImportView.error', {
|
|
||||||
'error': results['error']}));
|
|
||||||
this.$el.find('fieldset').removeClass('oe_closed');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (results['success']) {
|
|
||||||
if (this.getParent().getParent().active_view == "list") {
|
|
||||||
this.getParent().reload_content();
|
|
||||||
}
|
|
||||||
this.destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results['records']) {
|
|
||||||
var lines_to_skip = parseInt(this.$el.find('#csv_skip').val(), 10),
|
|
||||||
with_headers = this.$el.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
|
|
||||||
}));
|
|
||||||
this.$el.find('fieldset').addClass('oe_closed');
|
|
||||||
}
|
|
||||||
this.$el.find('form').removeClass('oe_import_no_result');
|
|
||||||
|
|
||||||
this.$el.delegate('.oe_m2o_drop_down_button', 'click', function () {
|
|
||||||
$(this).prev('input').focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.ready.then(function () {
|
|
||||||
var $fields = self.$el.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 field_name = self.match_column_to_field(header);
|
|
||||||
if (field_name) {
|
|
||||||
$fields.eq(index).val(field_name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
self.on_check_field_values();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Returns the name of the field (nested) matching the provided column name
|
|
||||||
*
|
|
||||||
* @param {String} name column name to look for
|
|
||||||
* @param {Array} [fields] fields to look into for the provided name
|
|
||||||
* @returns {String|undefined}
|
|
||||||
*/
|
|
||||||
match_column_to_field: function (name, fields) {
|
|
||||||
fields = fields || this.fields;
|
|
||||||
var f;
|
|
||||||
f = _(fields).detect(function (field) {
|
|
||||||
return field.name === name
|
|
||||||
});
|
|
||||||
if (!f) {
|
|
||||||
f = _(fields).detect(function (field) {
|
|
||||||
// TODO: levenshtein between header and field.string
|
|
||||||
return field.string.toLowerCase() === name.toLowerCase();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (f) { return f.name; }
|
|
||||||
|
|
||||||
// if ``name`` is a path (o2m), we need to recurse through its .fields
|
|
||||||
var index = name.indexOf('/');
|
|
||||||
if (index === -1) { return undefined; }
|
|
||||||
// Get the first path section, try to find the matching field
|
|
||||||
var column_name = name.substring(0, index);
|
|
||||||
f = _(fields).detect(function (field) {
|
|
||||||
// field.name for o2m is $foo/id, so we want to match on id
|
|
||||||
return field.id === column_name;
|
|
||||||
});
|
|
||||||
if (!f) {
|
|
||||||
f = _(fields).detect(function (field) {
|
|
||||||
return field.string.toLowerCase() === column_name.toLowerCase();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!f) { return undefined; }
|
|
||||||
|
|
||||||
// if we found a matching field for the first path section, recurse in
|
|
||||||
// its own .fields to try and get the rest of the path matched
|
|
||||||
var rest = this.match_column_to_field(
|
|
||||||
name.substring(index+1), f.fields);
|
|
||||||
if (!rest) { return undefined; }
|
|
||||||
return f.id + '/' + rest;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 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.$el.find(".sel_fields").each(function(index, element) {
|
|
||||||
var value = element.value;
|
|
||||||
var $el = $(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];
|
|
||||||
}
|
|
||||||
$el.add(same_valued_field).addClass('duplicate_fld');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return duplicates;
|
|
||||||
},
|
|
||||||
on_check_field_values: function () {
|
|
||||||
this.$el.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;">'+_t("Destination fields should only be selected once, some fields are selected more than once:")+'</div>').insertBefore(this.$el.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() {
|
|
||||||
var self = this;
|
|
||||||
if (!self.required_fields.length) { return true; }
|
|
||||||
|
|
||||||
// Resolve field id based on column name, as there may be
|
|
||||||
// several ways to provide the value for a given field and
|
|
||||||
// thus satisfy the requirement.
|
|
||||||
// (e.g. m2o_id or m2o_id/id columns may be provided)
|
|
||||||
var resolve_field_id = function(column_name) {
|
|
||||||
var f = _.detect(self.fields, function(field) {
|
|
||||||
return field.name === column_name;
|
|
||||||
});
|
|
||||||
if (!f) { return column_name; };
|
|
||||||
return f.id;
|
|
||||||
};
|
|
||||||
|
|
||||||
var selected_fields = _(this.$el.find('.sel_fields').get()).chain()
|
|
||||||
.pluck('value')
|
|
||||||
.compact()
|
|
||||||
.map(resolve_field_id)
|
|
||||||
.value();
|
|
||||||
|
|
||||||
var missing_fields = _.difference(this.required_fields, selected_fields);
|
|
||||||
if (missing_fields.length) {
|
|
||||||
this.$el.find("#result").before('<div id="message" style="color:red">' + _t("*Required Fields are not selected :") + missing_fields + '.</div>');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
destroy: function() {
|
|
||||||
this.$el.remove();
|
|
||||||
this._super();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -21,8 +21,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
||||||
// whether the view rows can be reordered (via vertical drag & drop)
|
// whether the view rows can be reordered (via vertical drag & drop)
|
||||||
'reorderable': true,
|
'reorderable': true,
|
||||||
'action_buttons': true,
|
'action_buttons': true,
|
||||||
// if true, the 'Import', 'Export', etc... buttons will be shown
|
|
||||||
'import_enabled': true,
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Core class for list-type displays.
|
* Core class for list-type displays.
|
||||||
|
@ -281,7 +279,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
||||||
self.reload_content();
|
self.reload_content();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add button and Import link
|
// Add button
|
||||||
if (!this.$buttons) {
|
if (!this.$buttons) {
|
||||||
this.$buttons = $(QWeb.render("ListView.buttons", {'widget':self}));
|
this.$buttons = $(QWeb.render("ListView.buttons", {'widget':self}));
|
||||||
if (this.options.$buttons) {
|
if (this.options.$buttons) {
|
||||||
|
@ -292,10 +290,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
||||||
this.$buttons.find('.oe_list_add')
|
this.$buttons.find('.oe_list_add')
|
||||||
.click(this.proxy('do_add_record'))
|
.click(this.proxy('do_add_record'))
|
||||||
.prop('disabled', grouped);
|
.prop('disabled', grouped);
|
||||||
this.$buttons.on('click', '.oe_list_button_import', function() {
|
|
||||||
self.on_sidebar_import();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pager
|
// Pager
|
||||||
|
@ -358,7 +352,6 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
|
||||||
this.sidebar = new instance.web.Sidebar(this);
|
this.sidebar = new instance.web.Sidebar(this);
|
||||||
this.sidebar.appendTo(this.options.$sidebar);
|
this.sidebar.appendTo(this.options.$sidebar);
|
||||||
this.sidebar.add_items('other', _.compact([
|
this.sidebar.add_items('other', _.compact([
|
||||||
self.is_action_enabled('create') && { label: _t("Import"), callback: this.on_sidebar_import },
|
|
||||||
{ label: _t("Export"), callback: this.on_sidebar_export },
|
{ label: _t("Export"), callback: this.on_sidebar_export },
|
||||||
self.is_action_enabled('delete') && { label: _t('Delete'), callback: this.do_delete_selected }
|
self.is_action_enabled('delete') && { label: _t('Delete'), callback: this.do_delete_selected }
|
||||||
]));
|
]));
|
||||||
|
|
|
@ -1249,9 +1249,6 @@ instance.web.View = instance.web.Widget.extend({
|
||||||
},
|
},
|
||||||
do_search: function(view) {
|
do_search: function(view) {
|
||||||
},
|
},
|
||||||
on_sidebar_import: function() {
|
|
||||||
new instance.web.DataImport(this, this.dataset).open();
|
|
||||||
},
|
|
||||||
on_sidebar_export: function() {
|
on_sidebar_export: function() {
|
||||||
new instance.web.DataExport(this, this.dataset).open();
|
new instance.web.DataExport(this, this.dataset).open();
|
||||||
},
|
},
|
||||||
|
|
|
@ -652,9 +652,6 @@
|
||||||
<button type="button" class="oe_button oe_list_add oe_highlight">
|
<button type="button" class="oe_button oe_list_add oe_highlight">
|
||||||
<t t-esc="widget.options.addable"/>
|
<t t-esc="widget.options.addable"/>
|
||||||
</button>
|
</button>
|
||||||
<span class="oe_alternative" t-if="widget.options.import_enabled">
|
|
||||||
<span class="oe_fade">or</span> <a href="#" class="oe_bold oe_list_button_import">Import</a>
|
|
||||||
</span>
|
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
<t t-name="ListView.pager">
|
<t t-name="ListView.pager">
|
||||||
|
@ -698,9 +695,10 @@
|
||||||
<t t-jquery="button.oe_list_add" t-operation="after">
|
<t t-jquery="button.oe_list_add" t-operation="after">
|
||||||
<button class="oe_button oe_list_save oe_highlight"
|
<button class="oe_button oe_list_save oe_highlight"
|
||||||
type="button">Save</button>
|
type="button">Save</button>
|
||||||
</t>
|
<span class="oe_alternative">
|
||||||
<t t-jquery="a.oe_list_button_import" t-operation="after">
|
<span class="oe_fade">or</span>
|
||||||
<a href="#" class="oe_bold oe_list_discard">Discard</a>
|
<a href="#" class="oe_bold oe_list_discard">Discard</a>
|
||||||
|
</span>
|
||||||
</t>
|
</t>
|
||||||
</t>
|
</t>
|
||||||
<t t-extend="ListView.row">
|
<t t-extend="ListView.row">
|
||||||
|
|
Loading…
Reference in New Issue