flectra/addons/web/static/src/js/widgets/data_export.js

482 lines
18 KiB
JavaScript

flectra.define('web.DataExport', function (require) {
"use strict";
var core = require('web.core');
var crash_manager = require('web.crash_manager');
var data = require('web.data');
var Dialog = require('web.Dialog');
var framework = require('web.framework');
var pyeval = require('web.pyeval');
var QWeb = core.qweb;
var _t = core._t;
var DataExport = Dialog.extend({
template: 'ExportDialog',
events: {
'click .o_expand_parent': function(e) {
this.on_expand_action(this.records[$(e.target).closest('.o_export_tree_item').data('id')]);
},
'click .o_export_tree_item': function(e) {
e.stopPropagation();
var $elem = $(e.currentTarget);
var row_index = $elem.prevAll('.o_export_tree_item').length;
var row_index_level = $elem.parents('.o_export_tree_item').length;
if(e.shiftKey && row_index_level === this.row_index_level) {
var minIndex = Math.min(row_index, this.row_index);
var maxIndex = Math.max(row_index, this.row_index);
this.$records.filter(function() { return ($elem.parent()[0] === $(this).parent()[0]); })
.slice(minIndex, maxIndex+1)
.addClass('o_selected')
.filter(':not(:last)')
.each(process_children);
}
this.row_index = row_index;
this.row_index_level = row_index_level;
if(e.ctrlKey) {
$elem.toggleClass('o_selected').focus();
} else if(e.shiftKey) {
$elem.addClass('o_selected').focus();
} else {
this.$(".o_selected").removeClass("o_selected")
$elem.addClass("o_selected").focus();
}
function process_children() {
var $this = $(this);
if($this.hasClass('open')) {
$this.children('.o_export_tree_item')
.addClass('o_selected')
.each(process_children);
}
}
},
'dblclick .o_export_tree_item': function(e) {
var $elem = $(e.currentTarget);
$elem.removeClass('o_selected');
this.add_field($elem.data('id'), $elem.find('.o_tree_column').first().text());
},
'keydown .o_export_tree_item': function(e) {
e.stopPropagation();
var $elem = $(e.currentTarget);
var record = this.records[$elem.data('id')];
switch(e.keyCode || e.which) {
case $.ui.keyCode.LEFT:
if ($elem.hasClass('open')) {
this.on_expand_action(record);
}
break;
case $.ui.keyCode.RIGHT:
if (!$elem.hasClass('open')) {
this.on_expand_action(record);
}
break;
case $.ui.keyCode.UP:
var $prev = $elem.prev('.o_export_tree_item');
if($prev.length === 1) {
while($prev.hasClass('open')) {
$prev = $prev.children('.o_export_tree_item').last();
}
} else {
$prev = $elem.parent('.o_export_tree_item');
if($prev.length === 0) {
break;
}
}
$elem.removeClass("o_selected").blur();
$prev.addClass("o_selected").focus();
break;
case $.ui.keyCode.DOWN:
var $next;
if($elem.hasClass('open')) {
$next = $elem.children('.o_export_tree_item').first();
} else {
$next = $elem.next('.o_export_tree_item');
if($next.length === 0) {
$next = $elem.parent('.o_export_tree_item').next('.o_export_tree_item');
if($next.length === 0) {
break;
}
}
}
$elem.removeClass("o_selected").blur();
$next.addClass("o_selected").focus();
break;
}
},
'click .o_add_field': function() {
var self = this;
this.$('.o_field_tree_structure .o_selected')
.removeClass('o_selected')
.each(function() {
var $this = $(this);
self.add_field($this.data('id'), $this.children('.o_tree_column').text());
});
},
'click .o_remove_field': function() {
this.$fields_list.find('option:selected').remove();
},
'click .o_remove_all_field': function() {
this.$fields_list.empty();
},
'click .o_move_up': function() {
var $selected_rows = this.$fields_list.find('option:selected');
var $prev_row = $selected_rows.first().prev();
if($prev_row.length){
$prev_row.before($selected_rows.detach());
}
},
'click .o_move_down': function () {
var $selected_rows = this.$fields_list.find('option:selected');
var $next_row = $selected_rows.last().next();
if($next_row.length){
$next_row.after($selected_rows.detach());
}
},
'click .o_toggle_save_list': function(e) {
e.preventDefault();
var $saveList = this.$(".o_save_list");
if($saveList.is(':empty')) {
$saveList.append(QWeb.render('Export.SaveList'));
} else {
if($saveList.is(':hidden')) {
$saveList.show();
$saveList.find(".o_export_list_input").val("");
} else {
$saveList.hide();
}
}
},
'click .o_save_list > button': function(e) {
var $saveList = this.$(".o_save_list");
var value = $saveList.find("input").val();
if(!value) {
Dialog.alert(this, _t("Please enter save field list name"));
return;
}
var fields = this.get_fields();
if (fields.length === 0) {
return;
}
$saveList.hide();
var self = this;
this.exports.create({
name: value,
resource: this.record.model,
export_fields: _.map(fields, function (field) {
return [0, 0, {name: field}];
}),
}).then(function(export_list_id) {
if(!export_list_id) {
return;
}
var $select = self.$(".o_exported_lists_select");
if($select.length === 0 || $select.is(":hidden")) {
self.show_exports_list();
}
$select.append(new Option(value, export_list_id));
});
},
},
init: function(parent, record) {
var options = {
title: _t("Export Data"),
buttons: [
{text: _t("Export To File"), click: this.export_data, classes: "btn-primary"},
{text: _t("Close"), close: true},
],
};
this._super(parent, options);
this.records = {};
this.record = record;
this.exports = new data.DataSetSearch(this, 'ir.exports', this.record.getContext());
this.row_index = 0;
this.row_index_level = 0;
},
start: function() {
var self = this;
var waitFor = [this._super.apply(this, arguments)];
// The default for the ".modal_content" element is "max-height: 100%;"
// but we want it to always expand to "height: 100%;" for this modal.
// This can be achieved thanks to LESS modification without touching
// the ".modal-content" rules... but not with Internet explorer (11).
this.$modal.find(".modal-content").css("height", "100%");
this.$fields_list = this.$('.o_fields_list');
this.$import_compat_radios = this.$('.o_import_compat input');
waitFor.push(this._rpc({route: '/web/export/formats'}).then(do_setup_export_formats));
var got_fields = new $.Deferred();
this.$import_compat_radios.change(function(e) {
self.$('.o_field_tree_structure').remove();
self._rpc({
route: '/web/export/get_fields',
params: {
model: self.record.model,
import_compat: !!$(e.target).val(),
},
})
.done(function (records) {
var compatible_fields = _.map(records, function (record) {return record.id; });
self.$fields_list
.find('option')
.filter(function () {
var option_field = $(this).attr('value');
if (compatible_fields.indexOf(option_field) === -1) {
return true;
}
})
.remove();
got_fields.resolve();
self.on_show_data(records);
});
}).eq(0).change();
waitFor.push(got_fields);
waitFor.push(this.getParent().getActiveDomain().then(function (domain) {
if (domain === undefined) {
self.ids_to_export = self.getParent().getSelectedIds();
self.domain = self.record.domain;
} else {
self.ids_to_export = false;
self.domain = domain;
}
self.on_show_domain();
}));
waitFor.push(this.show_exports_list());
return $.when.apply($, waitFor);
function do_setup_export_formats(formats) {
var $fmts = self.$('.o_export_format');
_.each(formats, function(format, i) {
var $radio = $('<input/>', {type: 'radio', value: format.tag, name: 'o_export_format_name'});
var $label = $('<label/>', {html: format.label});
if (format.error) {
$radio.prop('disabled', true);
$label.html(_.str.sprintf("%s — %s", format.label, format.error));
}
$fmts.append($("<div/>").append($radio, $label));
});
self.$export_format_inputs = $fmts.find('input');
self.$export_format_inputs.first().prop('checked', true);
}
},
show_exports_list: function() {
if (this.$('.o_exported_lists_select').is(':hidden')) {
this.$('.o_exported_lists').show();
return $.when();
}
var self = this;
return this._rpc({
model: 'ir.exports',
method: 'search_read',
fields: ['name'],
domain: [['resource', '=', this.record.model]]
}).then(function (export_list) {
if (!export_list.length) {
return;
}
self.$('.o_exported_lists').append(QWeb.render('Export.SavedList', {'existing_exports': export_list}));
self.$('.o_exported_lists_select').on('change', function() {
self.$fields_list.empty();
var export_id = self.$('.o_exported_lists_select option:selected').val();
if(export_id) {
self._rpc({
route: '/web/export/namelist',
params: {
model: self.record.model,
export_id: parseInt(export_id, 10),
},
})
.then(do_load_export_field);
}
});
self.$('.o_delete_exported_list').click(function() {
var select_exp = self.$('.o_exported_lists_select option:selected');
var options = {
confirm_callback: function () {
if (select_exp.val()) {
self.exports.unlink([parseInt(select_exp.val(), 10)]);
select_exp.remove();
self.$fields_list.empty();
if (self.$('.o_exported_lists_select option').length <= 1) {
self.$('.o_exported_lists').hide();
}
}
}
};
Dialog.confirm(this, _t("Do you really want to delete this export template?"), options);
});
});
function do_load_export_field(field_list) {
_.each(field_list, function (field) {
self.$fields_list.append(new Option(field.label, field.name));
});
}
},
on_expand_action: function(record) {
if(!record['children']) {
return;
}
var model = record['params']['model'];
var prefix = record['params']['prefix'];
var name = record['params']['name'];
var exclude_fields = [];
if(record['relation_field']) {
exclude_fields.push(record['relation_field']);
}
if(!record.loaded) {
var self = this;
this._rpc({
route: '/web/export/get_fields',
params: {
model: model,
prefix: prefix,
parent_name: name,
import_compat: !!this.$import_compat_radios.filter(':checked').val(),
parent_field_type : record['field_type'],
exclude: exclude_fields
},
})
.done(function(results) {
record.loaded = true;
self.on_show_data(results, record.id);
});
} else {
this.show_content(record.id);
}
},
on_show_domain: function() {
this.$('p').first()
.after(QWeb.render('Export.DomainMessage', {record: this}));
},
on_show_data: function(records, expansion) {
var self = this;
if(expansion) {
this.$('.o_export_tree_item[data-id="' + expansion + '"]')
.addClass('open')
.find('.o_expand_parent')
.toggleClass('fa-plus fa-minus')
.next()
.after(QWeb.render('Export.TreeItems', {'fields': records, 'debug': this.getSession().debug}));
} else {
this.$('.o_left_field_panel').empty().append(
$("<div/>").addClass('o_field_tree_structure')
.append(QWeb.render('Export.TreeItems', {'fields': records, 'debug': this.getSession().debug}))
);
}
_.extend(this.records, _.object(_.pluck(records, 'id'), records));
this.$records = this.$(".o_export_tree_item");
this.$records.each(function(i, el) {
var $elem = $(el);
$elem.find('.o_tree_column').first().toggleClass('o_required', !!self.records[$elem.data('id')].required);
});
},
show_content: function(id) {
var $this = this.$('.o_export_tree_item[data-id="' + id + '"]');
$this.toggleClass('open');
var is_open = $this.hasClass('open');
$this.children('.o_expand_parent').toggleClass('fa-minus', !!is_open).toggleClass('fa-plus', !is_open);
var $child_field = $this.find('.o_export_tree_item');
var child_len = (id.split("/")).length + 1;
for (var i = 0 ; i < $child_field.length ; i++) {
var $child = $child_field.eq(i);
if(!is_open) {
$child.hide();
} else if(child_len === $child_field.eq(i).data('id').split("/").length) {
if ($child.hasClass('open')) {
$child.removeClass('open');
$child.children('.o_expand_parent').removeClass('fa-minus').addClass('fa-plus');
}
$child.show();
}
}
},
add_field: function(field_id, string) {
var $field_list = this.$('.o_fields_list');
field_id = this.records[field_id].value || field_id;
if($field_list.find("option[value='" + field_id + "']").length === 0) {
$field_list.append(new Option(string, field_id));
}
},
get_fields: function() {
var $export_fields = this.$(".o_fields_list option").map(function() {
return $(this).val();
}).get();
if($export_fields.length === 0) {
Dialog.alert(this, _t("Please select fields to save export list..."));
}
return $export_fields;
},
export_data: function() {
var self = this;
var exported_fields = this.$('.o_fields_list option').map(function () {
return {
name: (self.records[this.value] || this).value,
label: this.textContent || this.innerText // DOM property is textContent, but IE8 only knows innerText
};
}).get();
if (_.isEmpty(exported_fields)) {
Dialog.alert(this, _t("Please select fields to export..."));
return;
}
exported_fields.unshift({name: 'id', label: _t('External ID')});
var export_format = this.$export_format_inputs.filter(':checked').val();
framework.blockUI();
this.getSession().get_file({
url: '/web/export/' + export_format,
data: {data: JSON.stringify({
model: this.record.model,
fields: exported_fields,
ids: this.ids_to_export,
domain: this.domain,
context: pyeval.eval('contexts', [this.record.getContext()]),
import_compat: !!this.$import_compat_radios.filter(':checked').val(),
})},
complete: framework.unblockUI,
error: crash_manager.rpc_error.bind(crash_manager),
});
},
});
return DataExport;
});