<commit_before>openerp.web.data_export = function(openerp) {
openerp.web.DataExport = openerp.web.Dialog.extend({
    template: 'ExportTreeView',
    dialog_title: 'Export Data',
    init: function(parent, dataset) {
        this._super(parent);
        this.records = {};
        this.dataset = dataset;
        this.exports = new openerp.web.DataSetSearch(
            this, 'ir.exports', this.dataset.get_context());
    },
    start: function() {
        var self = this;
        this._super.apply(this, arguments);
        this.open({
            modal: true,
            width: '55%',
            height: 'auto',
            position: 'top',
            buttons : {
                "Close" : function() {
                    self.close();
                  },
                "Export To File" : function() {
                    self.on_click_export_data();
                  }
               },
            close: function(event, ui){ self.close();}
        });
        self.$element.removeClass('ui-dialog-content ui-widget-content');
        self.$element.find('#add_field').click(function() {
            if ($('#field-tree-structure tr.ui-selected')) {
                var fld = self.$element.find('#field-tree-structure tr.ui-selected').find('a');
                for (var i = 0; i < fld.length; i++) {
                    var id = $(fld[i]).attr('id').split('-')[1];
                    var string = $(fld[i]).attr('string');
                    self.add_field(id, string);
                }
                self.$element.find('#field-tree-structure tr').removeClass('ui-selected');
            }
        });
        self.$element.find('#remove_field').click(function() {
            self.$element.find('#fields_list option:selected').remove();
        });
        self.$element.find('#remove_all_field').click(function() {
            self.$element.find('#fields_list').empty();
        });
        this.$element.find('#export_new_list').click(this.on_show_save_list);

        var got_fields = new $.Deferred();
        this.$element.find('#import_compat').change(function() {
            self.$element.find('#fields_list').empty();
            self.$element.find('#field-tree-structure').remove();
            var import_comp = self.$element.find("#import_compat").val();
            self.rpc("/web/export/get_fields", {
                model: self.dataset.model,
                import_compat: Boolean(import_comp)
            }, function (records) {
                got_fields.resolve();
                self.on_show_data(records);
            });
        }).change();

        return $.when(
            got_fields,
            this.rpc('/web/export/formats', {}, this.do_setup_export_formats),
            this.show_exports_list());
    },
    do_setup_export_formats: function (formats) {
        var $fmts = this.$element.find('#export_format');
        _(formats).each(function (format) {
            $fmts.append(new Option(format[1], format[0]));
        });
    },
    show_exports_list: function() {
        var self = this;
        if (self.$element.find('#saved_export_list').is(':hidden')) {
            self.$element.find('#ExistsExportList').show();
            return;
        }
        return this.exports.read_slice(['name'], {
            domain: [['resource', '=', this.dataset.model]]
        }, function (export_list) {
            if (!export_list.length) {
                return;
            }
            self.$element.find('#ExistsExportList').append(QWeb.render('Exists.ExportList', {'existing_exports': export_list}));
            self.$element.find('#saved_export_list').change(function() {
                self.$element.find('#fields_list option').remove();
                var export_id = self.$element.find('#saved_export_list option:selected').val();
                if (export_id) {
                    self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}, self.do_load_export_field);
                }
            });
            self.$element.find('#delete_export_list').click(function() {
                var select_exp = self.$element.find('#saved_export_list option:selected');
                if (select_exp.val()) {
                    self.exports.unlink([parseInt(select_exp.val(), 10)]);
                    select_exp.remove();
                    if (self.$element.find('#saved_export_list option').length <= 1) {
                        self.$element.find('#ExistsExportList').hide();
                    }
                }
            });
        });
    },
    do_load_export_field: function(field_list) {
        var export_node = this.$element.find("#fields_list");
        _(field_list).each(function (field) {
            export_node.append(new Option(field.label, field.name));
        });
    },
    on_show_save_list: function() {
        var self = this;
        var current_node = self.$element.find("#savenewlist");
        if (!(current_node.find("label")).length) {
            current_node.append(QWeb.render('ExportNewList'));
            current_node.find("#add_export_list").click(function() {
                var value = current_node.find("#savelist_name").val();
                if (value) {
                    self.do_save_export_list(value);
                } else {
                    alert("Pleae Enter Save Field List Name");
                }
            });
        } else {
            if (current_node.is(':hidden')) {
                current_node.show();
                current_node.find("#savelist_name").val("");
            } else {
               current_node.hide();
            }
        }
    },
    do_save_export_list: function(value) {
        var self = this;
        var fields = self.get_fields();
        if (!fields.length) {
            return;
        }
        this.exports.create({
            name: value,
            resource: this.dataset.model,
            export_fields: _(fields).map(function (field) {
                return [0, 0, {name: field}];
            })
        }, function (export_list_id) {
            if (!export_list_id) {
                return;
            }
            if (self.$element.find("#saved_export_list").length > 0) {
                self.$element.find("#saved_export_list").append(
                        new Option(value, export_list_id));
            } else {
                self.show_exports_list();
            }
            if (self.$element.find("#saved_export_list").is(":hidden")) {
                self.show_exports_list();
            }
        });
        this.on_show_save_list();
        this.$element.find("#fields_list option").remove();
    },
    on_click: function(id, record) {
        var self = this;
        if (!record['children']) {
            return;
        }
        var model = record['params']['model'],
            prefix = record['params']['prefix'],
            name = record['params']['name'];

        if (!record.loaded) {
            var import_comp = self.$element.find("#import_compat").val();
            self.rpc("/web/export/get_fields", {
                model: model,
                prefix: prefix,
                parent_name: name,
                import_compat: Boolean(import_comp),
                parent_field_type : record['field_type']
            }, function(results) {
                record.loaded = true;
                self.on_show_data(results, record.id);
            });
        } else {
            self.showcontent(record.id);
        }
    },
    on_show_data: function(result, after) {
        var self = this;
        var imp_cmpt = Boolean(self.$element.find("#import_compat").val());

        if (after) {
            var current_tr = self.$element.find("tr[id='treerow-" + after + "']");
            current_tr.addClass('open');
            current_tr.find('img').attr('src','/web/static/src/img/collapse.gif');
            current_tr.after(QWeb.render('ExportTreeView-Secondary.children', {'fields': result}));
        } else {
            self.$element.find('#left_field_panel').append(QWeb.render('ExportTreeView-Secondary', {'fields': result}));
        }
        _.each(result, function(record) {
            self.records[record.id] = record.value;
            if (record.required) {
                var required_fld = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
                required_fld.addClass("oe_export_requiredfield");
            }
            self.$element.find("img[id='parentimg-" + record.id +"']").click(function() {
                self.on_click(this.id, record);
            });

            self.$element.find("tr[id='treerow-" + record.id + "']").click(function(e) {
                if (e.shiftKey) {
                    var frst_click, scnd_click = '';
                    if (self.row_index == 0) {
                        self.row_index = this.rowIndex;
                        frst_click = self.$element.find("tr[id^='treerow-']")[self.row_index-1];
                        $(frst_click).addClass("ui-selected");
                    } else {
                        if (this.rowIndex >=self.row_index) {
                            for (var i = (self.row_index-1); i < this.rowIndex; i++) {
                                scnd_click = self.$element.find("tr[id^='treerow-']")[i];
                                if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
                                    $(scnd_click).addClass("ui-selected");
                                }
                            }
                        } else {
                            for (var i = (self.row_index-1); i >= (this.rowIndex-1); i--) {
                                scnd_click = self.$element.find("tr[id^='treerow-']")[i];
                                if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
                                    $(scnd_click).addClass("ui-selected");
                                }
                            }
                        }
                    }
                }
                self.row_index = this.rowIndex;

                self.$element.find("tr[id='treerow-" + record.id + "']").keyup(function() {
                    self.row_index = 0;
                });
                var o2m_selection = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
                if ($(o2m_selection).hasClass("oe_export_readonlyfield")) {
                    return false;
                }
                if (e.ctrlKey) {
                    if ($(this).hasClass('ui-selected')) {
                        $(this).removeClass('ui-selected').find('a').blur();
                    } else {
                        $(this).addClass('ui-selected').find('a').focus();
                    }
                } else if (!e.shiftKey) {
                    self.$element.find("tr.ui-selected")
                            .removeClass("ui-selected").find('a').blur();
                    $(this).addClass("ui-selected").find('a').focus();
                }
                return false;
            });

            self.$element.find("tr[id='treerow-" + record.id + "']").keydown(function(e) {
                var keyCode = e.keyCode || e.which;
                var arrow = {left: 37, up: 38, right: 39, down: 40 };
                switch (keyCode) {
                    case arrow.left:
                        if ($(this).hasClass('open')) {
                            self.on_click(this.id, record);
                        }
                        break;
                    case arrow.right:
                        if (!$(this).hasClass('open')) {
                            self.on_click(this.id, record);
                        }
                        break;
                    case arrow.up:
                        var elem = this;
                        $(elem).removeClass("ui-selected");
                        while (!$(elem).prev().is(":visible")) {
                            elem = $(elem).prev();
                        }
                        if (!$(elem).prev().find('#tree-column').hasClass("oe_export_readonlyfield")) {
                            $(elem).prev().addClass("ui-selected");
                        }
                        $(elem).prev().find('a').focus();
                        break;
                    case arrow.down:
                        var elem = this;
                        $(elem).removeClass("ui-selected");
                        while(!$(elem).next().is(":visible")) {
                            elem = $(elem).next();
                        }
                        if (!$(elem).next().find('#tree-column').hasClass("oe_export_readonlyfield")) {
                            $(elem).next().addClass("ui-selected");
                        }
                        $(elem).next().find('a').focus();
                        break;
                }
            });
            self.$element.find("tr[id='treerow-" + record.id + "']").dblclick(function() {
                var $o2m_selection = self.$element.find("tr[id^='treerow-" + record.id + "']").find('#tree-column');
                if (!$o2m_selection.hasClass("oe_export_readonlyfield")) {
                   self.add_field(record.id, $(this).find("a").attr("string"));
                }
            });
        });
        self.$element.find('#fields_list').mouseover(function(event) {
            if (event.relatedTarget) {
                if (event.relatedTarget.attributes['id'] && event.relatedTarget.attributes['string']) {
                    var field_id = event.relatedTarget.attributes["id"]["value"];
                    if (field_id && field_id.split("-")[0] === 'export') {
                        if (!self.$element.find("tr[id='treerow-" + field_id.split("-")[1] + "']").find('#tree-column').hasClass("oe_export_readonlyfield")) {
                            self.add_field(field_id.split("-")[1], event.relatedTarget.attributes["string"]["value"]);
                        }
                    }
                }
            }
        });
    },
    showcontent: function(id) {
        // show & hide the contents
        var $this = this.$element.find("tr[id='treerow-" + id + "']");
        var is_open = $this.hasClass('open');
        $this.toggleClass('open');

        var first_child = $this.find('img');
        if (is_open) {
            first_child.attr('src', '/web/static/src/img/expand.gif');
        } else {
            first_child.attr('src', '/web/static/src/img/collapse.gif');
        }
        var child_field = this.$element.find("tr[id^='treerow-" + id +"/']");
        var child_len = (id.split("/")).length + 1;
        for (var i = 0; i < child_field.length; i++) {
            var $child = $(child_field[i]);
            if (is_open) {
                $child.hide();
            } else if (child_len == (child_field[i].id.split("/")).length) {
                if ($child.hasClass('open')) {
                    $child.removeClass('open');
                    $child.find('img').attr('src', '/web/static/src/img/expand.gif');
                }
                $child.show();
            }
        }
    },
    add_field: function(field_id, string) {
        var field_list = this.$element.find('#fields_list');
        if (this.$element.find("#fields_list option[value='" + field_id + "']")
                && !this.$element.find("#fields_list option[value='" + field_id + "']").length) {
            field_list.append(new Option(string, field_id));
        }
    },
    get_fields: function() {
        var export_field = [];
        this.$element.find("#fields_list option").each(function() {
            export_field.push($(this).val());
        });
        if (!export_field.length) {
            alert('Please select fields to save export list...');
        }
        return export_field;
    },
    on_click_export_data: function() {
        $.blockUI(this.$element);
        var exported_fields = [], self = this;
        this.$element.find("#fields_list option").each(function() {
            var fieldname = self.records[$(this).val()];
            exported_fields.push({name: fieldname, label: $(this).text()});
        });
        if (_.isEmpty(exported_fields)) {
            alert('Please select fields to export...');
            return;
        }

        exported_fields.unshift({name: 'id', label: 'External ID'});
        var export_format = this.$element.find("#export_format").val();
        this.session.get_file({
            url: '/web/export/' + export_format,
            data: {data: JSON.stringify({
                model: this.dataset.model,
                fields: exported_fields,
                ids: this.dataset.ids,
                domain: this.dataset.domain,
                import_compat: Boolean(
                        this.$element.find("#import_compat").val())
            })},
            complete: $.unblockUI
        });
    },
    close: function() {
        $(this.$dialog).remove();
        this._super();
    }
});

};
<commit_msg>[FIX] breakage when trying to reload a just-saved exports list<commit_after>openerp.web.data_export = function(openerp) {
openerp.web.DataExport = openerp.web.Dialog.extend({
    template: 'ExportTreeView',
    dialog_title: 'Export Data',
    init: function(parent, dataset) {
        this._super(parent);
        this.records = {};
        this.dataset = dataset;
        this.exports = new openerp.web.DataSetSearch(
            this, 'ir.exports', this.dataset.get_context());
    },
    start: function() {
        var self = this;
        this._super.apply(this, arguments);
        this.open({
            modal: true,
            width: '55%',
            height: 'auto',
            position: 'top',
            buttons : {
                "Close" : function() {
                    self.close();
                  },
                "Export To File" : function() {
                    self.on_click_export_data();
                  }
               },
            close: function(event, ui){ self.close();}
        });
        self.$element.removeClass('ui-dialog-content ui-widget-content');
        self.$element.find('#add_field').click(function() {
            if ($('#field-tree-structure tr.ui-selected')) {
                var fld = self.$element.find('#field-tree-structure tr.ui-selected').find('a');
                for (var i = 0; i < fld.length; i++) {
                    var id = $(fld[i]).attr('id').split('-')[1];
                    var string = $(fld[i]).attr('string');
                    self.add_field(id, string);
                }
                self.$element.find('#field-tree-structure tr').removeClass('ui-selected');
            }
        });
        self.$element.find('#remove_field').click(function() {
            self.$element.find('#fields_list option:selected').remove();
        });
        self.$element.find('#remove_all_field').click(function() {
            self.$element.find('#fields_list').empty();
        });
        this.$element.find('#export_new_list').click(this.on_show_save_list);

        var got_fields = new $.Deferred();
        this.$element.find('#import_compat').change(function() {
            self.$element.find('#fields_list').empty();
            self.$element.find('#field-tree-structure').remove();
            var import_comp = self.$element.find("#import_compat").val();
            self.rpc("/web/export/get_fields", {
                model: self.dataset.model,
                import_compat: Boolean(import_comp)
            }, function (records) {
                got_fields.resolve();
                self.on_show_data(records);
            });
        }).change();

        return $.when(
            got_fields,
            this.rpc('/web/export/formats', {}, this.do_setup_export_formats),
            this.show_exports_list());
    },
    do_setup_export_formats: function (formats) {
        var $fmts = this.$element.find('#export_format');
        _(formats).each(function (format) {
            $fmts.append(new Option(format[1], format[0]));
        });
    },
    show_exports_list: function() {
        var self = this;
        if (self.$element.find('#saved_export_list').is(':hidden')) {
            self.$element.find('#ExistsExportList').show();
            return;
        }
        return this.exports.read_slice(['name'], {
            domain: [['resource', '=', this.dataset.model]]
        }, function (export_list) {
            if (!export_list.length) {
                return;
            }
            self.$element.find('#ExistsExportList').append(QWeb.render('Exists.ExportList', {'existing_exports': export_list}));
            self.$element.find('#saved_export_list').change(function() {
                self.$element.find('#fields_list option').remove();
                var export_id = self.$element.find('#saved_export_list option:selected').val();
                if (export_id) {
                    self.rpc('/web/export/namelist', {'model': self.dataset.model, export_id: parseInt(export_id)}, self.do_load_export_field);
                }
            });
            self.$element.find('#delete_export_list').click(function() {
                var select_exp = self.$element.find('#saved_export_list option:selected');
                if (select_exp.val()) {
                    self.exports.unlink([parseInt(select_exp.val(), 10)]);
                    select_exp.remove();
                    if (self.$element.find('#saved_export_list option').length <= 1) {
                        self.$element.find('#ExistsExportList').hide();
                    }
                }
            });
        });
    },
    do_load_export_field: function(field_list) {
        var export_node = this.$element.find("#fields_list");
        _(field_list).each(function (field) {
            export_node.append(new Option(field.label, field.name));
        });
    },
    on_show_save_list: function() {
        var self = this;
        var current_node = self.$element.find("#savenewlist");
        if (!(current_node.find("label")).length) {
            current_node.append(QWeb.render('ExportNewList'));
            current_node.find("#add_export_list").click(function() {
                var value = current_node.find("#savelist_name").val();
                if (value) {
                    self.do_save_export_list(value);
                } else {
                    alert("Pleae Enter Save Field List Name");
                }
            });
        } else {
            if (current_node.is(':hidden')) {
                current_node.show();
                current_node.find("#savelist_name").val("");
            } else {
               current_node.hide();
            }
        }
    },
    do_save_export_list: function(value) {
        var self = this;
        var fields = self.get_fields();
        if (!fields.length) {
            return;
        }
        this.exports.create({
            name: value,
            resource: this.dataset.model,
            export_fields: _(fields).map(function (field) {
                return [0, 0, {name: field}];
            })
        }, function (export_list_id) {
            if (!export_list_id.result) {
                return;
            }
            self.$element.find("#saved_export_list").append(
                    new Option(value, export_list_id.result));
            if (self.$element.find("#saved_export_list").is(":hidden")) {
                self.show_exports_list();
            }
        });
        this.on_show_save_list();
        this.$element.find("#fields_list option").remove();
    },
    on_click: function(id, record) {
        var self = this;
        if (!record['children']) {
            return;
        }
        var model = record['params']['model'],
            prefix = record['params']['prefix'],
            name = record['params']['name'];

        if (!record.loaded) {
            var import_comp = self.$element.find("#import_compat").val();
            self.rpc("/web/export/get_fields", {
                model: model,
                prefix: prefix,
                parent_name: name,
                import_compat: Boolean(import_comp),
                parent_field_type : record['field_type']
            }, function(results) {
                record.loaded = true;
                self.on_show_data(results, record.id);
            });
        } else {
            self.showcontent(record.id);
        }
    },
    on_show_data: function(result, after) {
        var self = this;
        var imp_cmpt = Boolean(self.$element.find("#import_compat").val());

        if (after) {
            var current_tr = self.$element.find("tr[id='treerow-" + after + "']");
            current_tr.addClass('open');
            current_tr.find('img').attr('src','/web/static/src/img/collapse.gif');
            current_tr.after(QWeb.render('ExportTreeView-Secondary.children', {'fields': result}));
        } else {
            self.$element.find('#left_field_panel').append(QWeb.render('ExportTreeView-Secondary', {'fields': result}));
        }
        _.each(result, function(record) {
            self.records[record.id] = record.value;
            if (record.required) {
                var required_fld = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
                required_fld.addClass("oe_export_requiredfield");
            }
            self.$element.find("img[id='parentimg-" + record.id +"']").click(function() {
                self.on_click(this.id, record);
            });

            self.$element.find("tr[id='treerow-" + record.id + "']").click(function(e) {
                if (e.shiftKey) {
                    var frst_click, scnd_click = '';
                    if (self.row_index == 0) {
                        self.row_index = this.rowIndex;
                        frst_click = self.$element.find("tr[id^='treerow-']")[self.row_index-1];
                        $(frst_click).addClass("ui-selected");
                    } else {
                        if (this.rowIndex >=self.row_index) {
                            for (var i = (self.row_index-1); i < this.rowIndex; i++) {
                                scnd_click = self.$element.find("tr[id^='treerow-']")[i];
                                if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
                                    $(scnd_click).addClass("ui-selected");
                                }
                            }
                        } else {
                            for (var i = (self.row_index-1); i >= (this.rowIndex-1); i--) {
                                scnd_click = self.$element.find("tr[id^='treerow-']")[i];
                                if (!$(scnd_click).find('#tree-column').hasClass("oe_export_readonlyfield")) {
                                    $(scnd_click).addClass("ui-selected");
                                }
                            }
                        }
                    }
                }
                self.row_index = this.rowIndex;

                self.$element.find("tr[id='treerow-" + record.id + "']").keyup(function() {
                    self.row_index = 0;
                });
                var o2m_selection = self.$element.find("tr[id='treerow-" + record.id + "']").find('#tree-column');
                if ($(o2m_selection).hasClass("oe_export_readonlyfield")) {
                    return false;
                }
                if (e.ctrlKey) {
                    if ($(this).hasClass('ui-selected')) {
                        $(this).removeClass('ui-selected').find('a').blur();
                    } else {
                        $(this).addClass('ui-selected').find('a').focus();
                    }
                } else if (!e.shiftKey) {
                    self.$element.find("tr.ui-selected")
                            .removeClass("ui-selected").find('a').blur();
                    $(this).addClass("ui-selected").find('a').focus();
                }
                return false;
            });

            self.$element.find("tr[id='treerow-" + record.id + "']").keydown(function(e) {
                var keyCode = e.keyCode || e.which;
                var arrow = {left: 37, up: 38, right: 39, down: 40 };
                switch (keyCode) {
                    case arrow.left:
                        if ($(this).hasClass('open')) {
                            self.on_click(this.id, record);
                        }
                        break;
                    case arrow.right:
                        if (!$(this).hasClass('open')) {
                            self.on_click(this.id, record);
                        }
                        break;
                    case arrow.up:
                        var elem = this;
                        $(elem).removeClass("ui-selected");
                        while (!$(elem).prev().is(":visible")) {
                            elem = $(elem).prev();
                        }
                        if (!$(elem).prev().find('#tree-column').hasClass("oe_export_readonlyfield")) {
                            $(elem).prev().addClass("ui-selected");
                        }
                        $(elem).prev().find('a').focus();
                        break;
                    case arrow.down:
                        var elem = this;
                        $(elem).removeClass("ui-selected");
                        while(!$(elem).next().is(":visible")) {
                            elem = $(elem).next();
                        }
                        if (!$(elem).next().find('#tree-column').hasClass("oe_export_readonlyfield")) {
                            $(elem).next().addClass("ui-selected");
                        }
                        $(elem).next().find('a').focus();
                        break;
                }
            });
            self.$element.find("tr[id='treerow-" + record.id + "']").dblclick(function() {
                var $o2m_selection = self.$element.find("tr[id^='treerow-" + record.id + "']").find('#tree-column');
                if (!$o2m_selection.hasClass("oe_export_readonlyfield")) {
                   self.add_field(record.id, $(this).find("a").attr("string"));
                }
            });
        });
        self.$element.find('#fields_list').mouseover(function(event) {
            if (event.relatedTarget) {
                if (event.relatedTarget.attributes['id'] && event.relatedTarget.attributes['string']) {
                    var field_id = event.relatedTarget.attributes["id"]["value"];
                    if (field_id && field_id.split("-")[0] === 'export') {
                        if (!self.$element.find("tr[id='treerow-" + field_id.split("-")[1] + "']").find('#tree-column').hasClass("oe_export_readonlyfield")) {
                            self.add_field(field_id.split("-")[1], event.relatedTarget.attributes["string"]["value"]);
                        }
                    }
                }
            }
        });
    },
    showcontent: function(id) {
        // show & hide the contents
        var $this = this.$element.find("tr[id='treerow-" + id + "']");
        var is_open = $this.hasClass('open');
        $this.toggleClass('open');

        var first_child = $this.find('img');
        if (is_open) {
            first_child.attr('src', '/web/static/src/img/expand.gif');
        } else {
            first_child.attr('src', '/web/static/src/img/collapse.gif');
        }
        var child_field = this.$element.find("tr[id^='treerow-" + id +"/']");
        var child_len = (id.split("/")).length + 1;
        for (var i = 0; i < child_field.length; i++) {
            var $child = $(child_field[i]);
            if (is_open) {
                $child.hide();
            } else if (child_len == (child_field[i].id.split("/")).length) {
                if ($child.hasClass('open')) {
                    $child.removeClass('open');
                    $child.find('img').attr('src', '/web/static/src/img/expand.gif');
                }
                $child.show();
            }
        }
    },
    add_field: function(field_id, string) {
        var field_list = this.$element.find('#fields_list');
        if (this.$element.find("#fields_list option[value='" + field_id + "']")
                && !this.$element.find("#fields_list option[value='" + field_id + "']").length) {
            field_list.append(new Option(string, field_id));
        }
    },
    get_fields: function() {
        var export_field = [];
        this.$element.find("#fields_list option").each(function() {
            export_field.push($(this).val());
        });
        if (!export_field.length) {
            alert('Please select fields to save export list...');
        }
        return export_field;
    },
    on_click_export_data: function() {
        $.blockUI(this.$element);
        var exported_fields = [], self = this;
        this.$element.find("#fields_list option").each(function() {
            var fieldname = self.records[$(this).val()];
            exported_fields.push({name: fieldname, label: $(this).text()});
        });
        if (_.isEmpty(exported_fields)) {
            alert('Please select fields to export...');
            return;
        }

        exported_fields.unshift({name: 'id', label: 'External ID'});
        var export_format = this.$element.find("#export_format").val();
        this.session.get_file({
            url: '/web/export/' + export_format,
            data: {data: JSON.stringify({
                model: this.dataset.model,
                fields: exported_fields,
                ids: this.dataset.ids,
                domain: this.dataset.domain,
                import_compat: Boolean(
                        this.$element.find("#import_compat").val())
            })},
            complete: $.unblockUI
        });
    },
    close: function() {
        $(this.$dialog).remove();
        this._super();
    }
});

};
<|endoftext|>


<commit_before>(function (angular, undefined) {
    'use strict';
    // module: hq.list_exports

    /* This module is for helping fetching and showing a list of exports,
     * and activating bulk export download, as well as single export download.
      * */

    var list_exports = angular.module('hq.list_exports', [
        'ngResource',
        'ngRoute',
        'ng.django.rmi',
        'ngMessages'
    ]);

    list_exports.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    }]);

    var exportsControllers = {};
    exportsControllers.ListExportsController = function (
        $scope, djangoRMI
    ) {
        /**
         * This controller fetches a list of saved exports from
         * subclasses of BaseExportListView.
         *
         * It also generates a list of exports selected for bulk exports.
         */

        var self = {};
        $scope._ = _;  // allow use of underscore.js within the template
        $scope.hasLoaded = false;
        $scope.exports = [];
        $scope.exportsListError = null;

        self._numTries = 0;
        self._getExportsList = function () {
            // The method below lives in the subclasses of
            // BaseExportListView.
            djangoRMI.get_exports_list({})
                .success(function (data) {
                    if (data.success) {
                        $scope.exports = data.exports;
                    } else {
                        $scope.exportsListError = data.error;
                    }
                    $scope.hasLoaded = true;
                })
                .error(function () {
                    // Retry in case the connection was flaky.
                    if (self._numTries > 3) {
                        $scope.hasLoaded = true;
                        $scope.exportsListError = 'default';
                    }
                    self._numTries ++;
                    self._getExportsList();
                });
        };
        self._getExportsList();

        // For Bulk Export
        $scope.showBulkExportDownload = false;
        $scope.bulkExportList = '';

        $scope.updateBulkStatus = function () {
            var selectedExports = _.filter($scope.exports, function (exp) {
                return !!exp.addedToBulk;
            });
            $scope.showBulkExportDownload = !_.isEmpty(selectedExports);
            $scope.bulkExportList = JSON.stringify(selectedExports);
            $('input[name="export_list"]').val(JSON.stringify(selectedExports));
        };
        $scope.selectAll = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = true;
            });
            $scope.updateBulkStatus();
        };
        $scope.selectNone = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = false;
            });
            $scope.updateBulkStatus();
        };
        $scope.updateEmailedExportData = function (component, exp) {
            $('#modalRefreshExportConfirm-' + exp.id + '-' + component.groupId).modal('hide');
            component.updatingData = true;
            djangoRMI.update_emailed_export_data({
                'component': component,
                'export': exp
            })
                .success(function (data) {
                    if (data.success) {
                        component.updatingData = false;
                        component.updatedDataTriggered = true;
                    }
                });
        };
    };

    list_exports.controller(exportsControllers);

}(window.angular));
<commit_msg>fix minor errors<commit_after>(function (angular, undefined) {
    'use strict';
    // module: hq.list_exports

    /* This module is for helping fetching and showing a list of exports,
     * and activating bulk export download, as well as single export download.
      * */

    var list_exports = angular.module('hq.list_exports', [
        'ngResource',
        'ngRoute',
        'ng.django.rmi',
        'ngMessages'
    ]);

    list_exports.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    }]);

    var exportsControllers = {};
    exportsControllers.ListExportsController = function (
        $scope, djangoRMI
    ) {
        /**
         * This controller fetches a list of saved exports from
         * subclasses of BaseExportListView.
         *
         * It also generates a list of exports selected for bulk exports.
         */

        var self = {};
        $scope._ = _;  // allow use of underscore.js within the template
        $scope.hasLoaded = false;
        $scope.exports = [];
        $scope.exportsListError = null;

        self._numTries = 0;
        self._getExportsList = function () {
            // The method below lives in the subclasses of
            // BaseExportListView.
            djangoRMI.get_exports_list({})
                .success(function (data) {
                    if (data.success) {
                        $scope.exports = data.exports;
                    } else {
                        $scope.exportsListError = data.error;
                    }
                    $scope.hasLoaded = true;
                })
                .error(function () {
                    // Retry in case the connection was flaky.
                    if (self._numTries > 3) {
                        $scope.hasLoaded = true;
                        $scope.exportsListError = 'default';
                        return;
                    }
                    self._numTries ++;
                    self._getExportsList();
                });
        };
        self._getExportsList();

        // For Bulk Export
        $scope.showBulkExportDownload = false;
        $scope.bulkExportList = '[]';

        $scope.updateBulkStatus = function () {
            var selectedExports = _.filter($scope.exports, function (exp) {
                return !!exp.addedToBulk;
            });
            $scope.showBulkExportDownload = !_.isEmpty(selectedExports);
            $scope.bulkExportList = JSON.stringify(selectedExports);
            $('input[name="export_list"]').val(JSON.stringify(selectedExports));
        };
        $scope.selectAll = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = true;
            });
            $scope.updateBulkStatus();
        };
        $scope.selectNone = function () {
            _.each($scope.exports, function (exp) {
                exp.addedToBulk = false;
            });
            $scope.updateBulkStatus();
        };
        $scope.updateEmailedExportData = function (component, exp) {
            $('#modalRefreshExportConfirm-' + exp.id + '-' + component.groupId).modal('hide');
            component.updatingData = true;
            djangoRMI.update_emailed_export_data({
                'component': component,
                'export': exp
            })
                .success(function (data) {
                    if (data.success) {
                        component.updatingData = false;
                        component.updatedDataTriggered = true;
                    }
                });
        };
    };

    list_exports.controller(exportsControllers);

}(window.angular));
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { injectIntl, FormattedHTMLMessage } from 'react-intl';
import { connect } from 'react-redux';
import { Grid, Row, Col } from 'react-flexbox-grid/lib';
import { selectQuery, resetSelected, resetQueries, resetSentenceCounts, resetSampleStories, resetStoryCounts,
  resetGeo, updateTimestampForQueries, removeDeletedQueries } from '../../../actions/explorerActions';
import QueryPickerContainer from './QueryPickerContainer';
import QueryResultsContainer from '../results/QueryResultsContainer';
import { WarningNotice } from '../../common/Notice';
import composeUrlBasedQueryContainer from '../UrlBasedQueryContainer';
import PageTitle from '../../common/PageTitle';

const localMessages = {
  register: { id: 'explorer.queryBuilder.urlParams', defaultMessage: 'Register for a free Media Cloud account to get access to all the Explorer features! Register Now' },
  title: { id: 'explorer.queryBuilder.sampleTitle', defaultMessage: 'Search Demo' },
};

class DemoQueryBuilderContainer extends React.Component {
  componentWillMount() {
    const { selectFirstQuery, queries } = this.props;
    // console.log(queries[0]);
    selectFirstQuery(queries[0]); // on first load select first by default so the builder knows which one to render in the form
  }

  /*
  componentWillUnmount() {
    const { resetExplorerData } = this.props;
    resetExplorerData();
  }
  */

  render() {
    const { queries, handleSearch, samples, location, lastSearchTime } = this.props;
    const isEditable = location.pathname.includes('queries/demo/search');
    return (

        <PageTitle value={localMessages.title} />

          <Grid>
            <Row>
              <Col lg={12}>
                <WarningNotice>
                  <FormattedHTMLMessage {...localMessages.register} />
                </WarningNotice>
              </Col>
            </Row>
          </Grid>

        <QueryPickerContainer isEditable={isEditable} onSearch={() => handleSearch()} />
        <QueryResultsContainer
          lastSearchTime={lastSearchTime}
          queries={queries}
          samples={samples}
          onSearch={() => handleSearch()}
        />

    );
  }
}

DemoQueryBuilderContainer.propTypes = {
  intl: PropTypes.object.isRequired,
  // from parent
  initialValues: PropTypes.object,
  // from state
  location: PropTypes.object,
  queries: PropTypes.array.isRequired,
  samples: PropTypes.array,
  lastSearchTime: PropTypes.number,
  resetExplorerData: PropTypes.func.isRequired,
  selectFirstQuery: PropTypes.func,

  handleSearch: PropTypes.func.isRequired,
};

const mapStateToProps = state => ({
  queries: state.explorer.queries.queries,
  lastSearchTime: state.explorer.lastSearchTime.time,
  samples: state.explorer.samples.list,
});

// push any updates (including selected) into queries in state, will trigger async load in sub sections
const mapDispatchToProps = dispatch => ({
  resetExplorerData: () => { // TODO we will reduce this down to one call
    dispatch(resetSelected());
    dispatch(resetQueries());
    dispatch(resetSentenceCounts());
    dispatch(resetSampleStories());
    dispatch(resetStoryCounts());
    dispatch(resetGeo());
  },
  selectFirstQuery: (query) => {
    dispatch(selectQuery(query));
  },
  reallyHandleSearch: () => {
    dispatch(removeDeletedQueries());
    dispatch(updateTimestampForQueries());
  },
});

function mergeProps(stateProps, dispatchProps, ownProps) {
  return Object.assign({}, stateProps, dispatchProps, ownProps, {
    handleSearch: () => {
      dispatchProps.reallyHandleSearch(stateProps.queries);
    },
  });
}

export default
injectIntl(
  connect(mapStateToProps, mapDispatchToProps, mergeProps)(
    composeUrlBasedQueryContainer()(
      DemoQueryBuilderContainer
    )
  )
);
<commit_msg>remove new state in DemoQueryContainer so demo new queries render correclty<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { injectIntl, FormattedHTMLMessage } from 'react-intl';
import { connect } from 'react-redux';
import { Grid, Row, Col } from 'react-flexbox-grid/lib';
import { selectQuery, resetSelected, resetQueries, resetSentenceCounts, resetSampleStories, resetStoryCounts,
  resetGeo, updateTimestampForQueries, removeNewStatusFromQueries, removeDeletedQueries } from '../../../actions/explorerActions';
import QueryPickerContainer from './QueryPickerContainer';
import QueryResultsContainer from '../results/QueryResultsContainer';
import { WarningNotice } from '../../common/Notice';
import composeUrlBasedQueryContainer from '../UrlBasedQueryContainer';
import PageTitle from '../../common/PageTitle';

const localMessages = {
  register: { id: 'explorer.queryBuilder.urlParams', defaultMessage: 'Register for a free Media Cloud account to get access to all the Explorer features! Register Now' },
  title: { id: 'explorer.queryBuilder.sampleTitle', defaultMessage: 'Search Demo' },
};

class DemoQueryBuilderContainer extends React.Component {
  componentWillMount() {
    const { selectFirstQuery, queries } = this.props;
    // console.log(queries[0]);
    selectFirstQuery(queries[0]); // on first load select first by default so the builder knows which one to render in the form
  }

  /*
  componentWillUnmount() {
    const { resetExplorerData } = this.props;
    resetExplorerData();
  }
  */

  render() {
    const { queries, handleSearch, samples, location, lastSearchTime } = this.props;
    const isEditable = location.pathname.includes('queries/demo/search');
    return (

        <PageTitle value={localMessages.title} />

          <Grid>
            <Row>
              <Col lg={12}>
                <WarningNotice>
                  <FormattedHTMLMessage {...localMessages.register} />
                </WarningNotice>
              </Col>
            </Row>
          </Grid>

        <QueryPickerContainer isEditable={isEditable} onSearch={() => handleSearch()} />
        <QueryResultsContainer
          lastSearchTime={lastSearchTime}
          queries={queries}
          samples={samples}
          onSearch={() => handleSearch()}
        />

    );
  }
}

DemoQueryBuilderContainer.propTypes = {
  intl: PropTypes.object.isRequired,
  // from parent
  initialValues: PropTypes.object,
  // from state
  location: PropTypes.object,
  queries: PropTypes.array.isRequired,
  samples: PropTypes.array,
  lastSearchTime: PropTypes.number,
  resetExplorerData: PropTypes.func.isRequired,
  selectFirstQuery: PropTypes.func,

  handleSearch: PropTypes.func.isRequired,
};

const mapStateToProps = state => ({
  queries: state.explorer.queries.queries,
  lastSearchTime: state.explorer.lastSearchTime.time,
  samples: state.explorer.samples.list,
});

// push any updates (including selected) into queries in state, will trigger async load in sub sections
const mapDispatchToProps = dispatch => ({
  resetExplorerData: () => { // TODO we will reduce this down to one call
    dispatch(resetSelected());
    dispatch(resetQueries());
    dispatch(resetSentenceCounts());
    dispatch(resetSampleStories());
    dispatch(resetStoryCounts());
    dispatch(resetGeo());
  },
  selectFirstQuery: (query) => {
    dispatch(selectQuery(query));
  },
  reallyHandleSearch: () => {
    dispatch(removeDeletedQueries());
    dispatch(removeNewStatusFromQueries());
    dispatch(updateTimestampForQueries());
  },
});

function mergeProps(stateProps, dispatchProps, ownProps) {
  return Object.assign({}, stateProps, dispatchProps, ownProps, {
    handleSearch: () => {
      dispatchProps.reallyHandleSearch(stateProps.queries);
    },
  });
}

export default
injectIntl(
  connect(mapStateToProps, mapDispatchToProps, mergeProps)(
    composeUrlBasedQueryContainer()(
      DemoQueryBuilderContainer
    )
  )
);
<|endoftext|>


<commit_before>import { sendGoogleAnalyticsEvent } from './googleAnalytics.js';
import { previewEndTime, previewStartTime } from './mediaPlayer.js';
import { convertHHMMSSToSeconds, convertSecToHHMMSS, isHHMMSS,
         isInt, isUUID } from './utility.js';

export function initClipper () {

  $('#make-clip-start-time i, #make-clip-start-time div').on('click', function () {
    var startTime = $('#make-clip-start-time input').val() || "0";
    var endTime = $('#make-clip-end-time input').val();
    startTime = convertHHMMSSToSeconds(startTime);
    endTime = convertHHMMSSToSeconds(endTime);
    previewStartTime(startTime, endTime);
  });

  $('#make-clip-end-time i, #make-clip-end-time div').on('click', function () {
    var endTime = $('#make-clip-end-time input').val() || "3";
    endTime = convertHHMMSSToSeconds(endTime);
    previewEndTime(endTime);
  });

  $('#make-clip-time-set').on('click', function () {
    var currentTimeHHMMSS = convertSecToHHMMSS(Math.floor(audio.currentTime));
    var currentSetMode = $('#make-clip-time-set').html();
    if (currentSetMode === 'Set Start') {
      $('#make-clip-start-time input').val(currentTimeHHMMSS);
      $('#make-clip-end-time input').focus();
      $('#make-clip-time-set').html('Set End');
      sendGoogleAnalyticsEvent('Make Clip', 'Set End button clicked')
    } else if (currentSetMode === 'Set End') {
      $('#make-clip-end-time input').val(currentTimeHHMMSS);
      $('#make-clip-time-set').html('Set Start');
      $('#make-clip-title textarea').focus();
      sendGoogleAnalyticsEvent('Make Clip', 'Set Start button clicked')
    }
  });

  $('#player').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-set').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-forwards').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('click', function () {
    audio.currentTime = audio.currentTime - 15;
  });

  $('#make-clip-time-forwards').on('click', function () {
    audio.currentTime = audio.currentTime + 15;
  });

}

export function setStartTime () {
  $('#make-clip-start-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-end-time input').focus();
}

export function setEndTime () {
  $('#make-clip-end-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-title textarea').focus();
}

export function toggleMakeClipWidget (_this) {
  if ($('#add-to-playlist').css('display') !== 'block' && $('#recommend').css('display') !== 'block') {
    $('#player-description-truncated').hide();
    $('#player-description-full').hide();
    $('#playlist').hide();
  }

  if ($(_this).hasClass('active')) {
    $('#player-description-truncated').show();
    $('#playlist').show();
  }

  $('#add-to-playlist').hide();
  $('#toggle-playlist-btn').removeClass('active');

  $('#recommend').hide();
  $('#toggle-recommend-btn').removeClass('active');

  $('#toggle-make-clip-btn').toggleClass('active');
  $('#make-clip').toggle();

  sendGoogleAnalyticsEvent('Make Clip', 'Toggle Make Clip Widget');
}

export function makeClip (event) {
  event.preventDefault();

  sendGoogleAnalyticsEvent('Make Clip', 'Make Clip');

  $('#make-clip-start-time-error').hide();
  $('#make-clip-end-time-error').hide();
  $('#make-clip-start-time').removeClass('has-danger');
  $('#make-clip-end-time').removeClass('has-danger');
  $('#make-clip-time').removeClass('has-danger');

  var startTime = $('#make-clip-start-time input').val(),
      endTime = $('#make-clip-end-time input').val();

  if (startTime === '' && endTime === '') {
    $('#make-clip-start-time-error').html('Type a start time and/or end time to create a clip.');
    $('#make-clip-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(startTime) && startTime !== '') {
    $('#make-clip-start-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(endTime) && endTime !== '') {
    $('#make-clip-end-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-end-time-error').show();
    return;
  }

  startTime = convertHHMMSSToSeconds(startTime);
  endTime = convertHHMMSSToSeconds(endTime);

  if (startTime === 0 && (endTime === 0 || endTime === null)) {
    $('#make-clip-start-time-error').html('Type a start or end time.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (endTime === 0) {
    endTime = null;
  }

  if (startTime === endTime) {
    $('#make-clip-start-time-error').html('Start time and end time cannot be the same.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (endTime !== null && endTime <= startTime) {
    $('#make-clip-start-time-error').html('End time cannot be earlier than start time.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  // After the form is validated, display loading state and prevent resubmit
  if (window.preventResubmit) { return }
  window.preventResubmit = true;
  $('#make-clip-btn').attr('disabled', true);
  $('#make-clip-btn').html('')

  // TODO: how can we prevent malicious scripts in the title?
  var clipTitle = $('#make-clip-title textarea').val();

  // TODO: set owner name based on ownerId
  var ownerName = 'random owner name';

  if (endTime === "") {
    endTime = null;
  }

  // TODO: HACK: DANGER WILL ROBINSON: passing window variables into a POST
  // can't be a good idea. Should seriously consider fixing this...

  let dataObj = {
    startTime: startTime,
    endTime: endTime,
    title: clipTitle,
    ownerName: ownerName,
    podcastFeedURL: window.podcastFeedURL,
    podcastTitle: window.podcastTitle,
    episodeMediaURL: window.episodeMediaURL,
    episodeTitle: window.episodeTitle,
    episodePubDate: window.episodePubDate,
    episodeSummary: window.episodeSummary,
    episodeDuration: window.episodeDuration
  }

  if (window.podcastImageURL && window.podcastImageURL.indexOf('http') === 0) {
    dataObj.podcastImageURL = window.podcastImageURL;
  }

  if (window.episodeImageURL && window.episodeImageURL.indexOf('http') === 0) {
    dataObj.episodeImageURL = window.episodeImageURL;
  }

  setTimeout(function () {
    $.ajax({
      type: 'POST',
      url: '/clips',
      headers: {
        Authorization: $.cookie('idToken')
      },
      data: dataObj,
      success: function (response) {
        if (window.isPlayerPage) {
          toggleMakeClipWidget();
          $('#playlist').show();
          $('#make-clip-start-time input').val('');
          $('#make-clip-end-time input').val('');
          $('#make-clip-title textarea').val('');
          $('#player-description-truncated').show();
          $('#clip-created-modal-link').val(location.protocol + '\/\/' + location.hostname + (location.port ? ':'+location.port: '')  + '\/clips\/' + response.id);
          $('#clip-created-modal').attr('data-id', response.id);
          $('#clip-created-modal').modal('show');
        } else {
          location.href = '\/clips\/' + response.id;
        }
      },
      error: function (xhr, status, error) {
        console.log(error);
        alert('Failed to create clip. Please check your internet connection and try again.');
      },
      complete: function () {
        window.preventResubmit = false;
        $('#make-clip-btn').removeAttr('disabled');
        $('#make-clip-btn').html('Save');
      }
    });
  }, 3000);

}

export function requestClipsFromAPI(params) {
  return new Promise ((resolve, reject) => {
    let data = { podcastFeedURL: params.podcastFeedURL };

    if (params.episodeMediaURL) {
      data.episodeMediaURL = params.episodeMediaURL;
    }

    if (params.filterType) {
      data.filterType = params.filterType;
    }

    $.ajax({
      type: 'POST',
      url: '/api/clips',
      data: data,
      success: function (result) {
        resolve(result);
      },
      error: function (xhr, status, error) {
        reject(error);
      }
    });
  });
}
<commit_msg>Remove seemingly unnecessary 3 sec timeout before making a clip...<commit_after>import { sendGoogleAnalyticsEvent } from './googleAnalytics.js';
import { previewEndTime, previewStartTime } from './mediaPlayer.js';
import { convertHHMMSSToSeconds, convertSecToHHMMSS, isHHMMSS,
         isInt, isUUID } from './utility.js';

export function initClipper () {

  $('#make-clip-start-time i, #make-clip-start-time div').on('click', function () {
    var startTime = $('#make-clip-start-time input').val() || "0";
    var endTime = $('#make-clip-end-time input').val();
    startTime = convertHHMMSSToSeconds(startTime);
    endTime = convertHHMMSSToSeconds(endTime);
    previewStartTime(startTime, endTime);
  });

  $('#make-clip-end-time i, #make-clip-end-time div').on('click', function () {
    var endTime = $('#make-clip-end-time input').val() || "3";
    endTime = convertHHMMSSToSeconds(endTime);
    previewEndTime(endTime);
  });

  $('#make-clip-time-set').on('click', function () {
    var currentTimeHHMMSS = convertSecToHHMMSS(Math.floor(audio.currentTime));
    var currentSetMode = $('#make-clip-time-set').html();
    if (currentSetMode === 'Set Start') {
      $('#make-clip-start-time input').val(currentTimeHHMMSS);
      $('#make-clip-end-time input').focus();
      $('#make-clip-time-set').html('Set End');
      sendGoogleAnalyticsEvent('Make Clip', 'Set End button clicked')
    } else if (currentSetMode === 'Set End') {
      $('#make-clip-end-time input').val(currentTimeHHMMSS);
      $('#make-clip-time-set').html('Set Start');
      $('#make-clip-title textarea').focus();
      sendGoogleAnalyticsEvent('Make Clip', 'Set Start button clicked')
    }
  });

  $('#player').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-set').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-forwards').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('click', function () {
    audio.currentTime = audio.currentTime - 15;
  });

  $('#make-clip-time-forwards').on('click', function () {
    audio.currentTime = audio.currentTime + 15;
  });

}

export function setStartTime () {
  $('#make-clip-start-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-end-time input').focus();
}

export function setEndTime () {
  $('#make-clip-end-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-title textarea').focus();
}

export function toggleMakeClipWidget (_this) {
  if ($('#add-to-playlist').css('display') !== 'block' && $('#recommend').css('display') !== 'block') {
    $('#player-description-truncated').hide();
    $('#player-description-full').hide();
    $('#playlist').hide();
  }

  if ($(_this).hasClass('active')) {
    $('#player-description-truncated').show();
    $('#playlist').show();
  }

  $('#add-to-playlist').hide();
  $('#toggle-playlist-btn').removeClass('active');

  $('#recommend').hide();
  $('#toggle-recommend-btn').removeClass('active');

  $('#toggle-make-clip-btn').toggleClass('active');
  $('#make-clip').toggle();

  sendGoogleAnalyticsEvent('Make Clip', 'Toggle Make Clip Widget');
}

export function makeClip (event) {
  event.preventDefault();

  sendGoogleAnalyticsEvent('Make Clip', 'Make Clip');

  $('#make-clip-start-time-error').hide();
  $('#make-clip-end-time-error').hide();
  $('#make-clip-start-time').removeClass('has-danger');
  $('#make-clip-end-time').removeClass('has-danger');
  $('#make-clip-time').removeClass('has-danger');

  var startTime = $('#make-clip-start-time input').val(),
      endTime = $('#make-clip-end-time input').val();

  if (startTime === '' && endTime === '') {
    $('#make-clip-start-time-error').html('Type a start time and/or end time to create a clip.');
    $('#make-clip-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(startTime) && startTime !== '') {
    $('#make-clip-start-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(endTime) && endTime !== '') {
    $('#make-clip-end-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-end-time-error').show();
    return;
  }

  startTime = convertHHMMSSToSeconds(startTime);
  endTime = convertHHMMSSToSeconds(endTime);

  if (startTime === 0 && (endTime === 0 || endTime === null)) {
    $('#make-clip-start-time-error').html('Type a start or end time.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (endTime === 0) {
    endTime = null;
  }

  if (startTime === endTime) {
    $('#make-clip-start-time-error').html('Start time and end time cannot be the same.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (endTime !== null && endTime <= startTime) {
    $('#make-clip-start-time-error').html('End time cannot be earlier than start time.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  // After the form is validated, display loading state and prevent resubmit
  if (window.preventResubmit) { return }
  window.preventResubmit = true;
  $('#make-clip-btn').attr('disabled', true);
  $('#make-clip-btn').html('')

  // TODO: how can we prevent malicious scripts in the title?
  var clipTitle = $('#make-clip-title textarea').val();

  // TODO: set owner name based on ownerId
  var ownerName = 'random owner name';

  if (endTime === "") {
    endTime = null;
  }

  // TODO: HACK: DANGER WILL ROBINSON: passing window variables into a POST
  // can't be a good idea. Should seriously consider fixing this...

  let dataObj = {
    startTime: startTime,
    endTime: endTime,
    title: clipTitle,
    ownerName: ownerName,
    podcastFeedURL: window.podcastFeedURL,
    podcastTitle: window.podcastTitle,
    episodeMediaURL: window.episodeMediaURL,
    episodeTitle: window.episodeTitle,
    episodePubDate: window.episodePubDate,
    episodeSummary: window.episodeSummary,
    episodeDuration: window.episodeDuration
  }

  if (window.podcastImageURL && window.podcastImageURL.indexOf('http') === 0) {
    dataObj.podcastImageURL = window.podcastImageURL;
  }

  if (window.episodeImageURL && window.episodeImageURL.indexOf('http') === 0) {
    dataObj.episodeImageURL = window.episodeImageURL;
  }

  // TODO: was this surrounded in a setTimeout for a good reason? wth :(
  // setTimeout(function () {
    $.ajax({
      type: 'POST',
      url: '/clips',
      headers: {
        Authorization: $.cookie('idToken')
      },
      data: dataObj,
      success: function (response) {
        if (window.isPlayerPage) {
          toggleMakeClipWidget();
          $('#playlist').show();
          $('#make-clip-start-time input').val('');
          $('#make-clip-end-time input').val('');
          $('#make-clip-title textarea').val('');
          $('#player-description-truncated').show();
          $('#clip-created-modal-link').val(location.protocol + '\/\/' + location.hostname + (location.port ? ':'+location.port: '')  + '\/clips\/' + response.id);
          $('#clip-created-modal').attr('data-id', response.id);
          $('#clip-created-modal').modal('show');
        } else {
          location.href = '\/clips\/' + response.id;
        }
      },
      error: function (xhr, status, error) {
        console.log(error);
        alert('Failed to create clip. Please check your internet connection and try again.');
      },
      complete: function () {
        window.preventResubmit = false;
        $('#make-clip-btn').removeAttr('disabled');
        $('#make-clip-btn').html('Save');
      }
    });
  // }, 3000);

}

export function requestClipsFromAPI(params) {
  return new Promise ((resolve, reject) => {
    let data = { podcastFeedURL: params.podcastFeedURL };

    if (params.episodeMediaURL) {
      data.episodeMediaURL = params.episodeMediaURL;
    }

    if (params.filterType) {
      data.filterType = params.filterType;
    }

    $.ajax({
      type: 'POST',
      url: '/api/clips',
      data: data,
      success: function (result) {
        resolve(result);
      },
      error: function (xhr, status, error) {
        reject(error);
      }
    });
  });
}
<|endoftext|>


<commit_before>(function () {
    var components = {
        'inline-edit': 'hqwebapp/js/components/inline_edit',
        'pagination': 'hqwebapp/js/components/pagination'
    };

    _.each(components, function(moduleName, elementName) {
        ko.components.register(elementName, hqImport(moduleName));
    });

    $(function() {
        _.each(_.keys(components), function(elementName) {
            _.each($(elementName), function(el) {
                var $el = $(el);
                if (!$el.closest('.ko-template').length) {
                    $(el).koApplyBindings();
                }
            });
        });
    });
}());
<commit_msg>Only apply bindings to standalone components<commit_after>(function () {
    // standalone components will have their own knockout bindings. Use
    // standalone: false if you want to mix the component into another model
    var components = {
        'inline-edit': {path: 'hqwebapp/js/components/inline_edit', standalone: true},
        'pagination': {path: 'hqwebapp/js/components/pagination', standalone: false},
    };

    _.each(components, function(module, elementName) {
        ko.components.register(elementName, hqImport(module.path));
    });

    $(function() {
        _.each(components, function(module, elementName) {
            if (module.standalone){
                _.each($(elementName), function(el) {
                    var $el = $(el);
                    if (!$el.closest('.ko-template').length) {
                        $(el).koApplyBindings();
                    }
                });
            }
        });
    });
}());
<|endoftext|>


<commit_before>openerp.web.data_import = function(openerp) {
var QWeb = openerp.web.qweb,
    _t = openerp.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);
}

openerp.web.DataImport = openerp.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('name')
                .value();
            convert_fields(self);
            self.all_fields.sort();
        });
    },
    start: function() {
        var self = this;
        this._super();
        this.open({
            buttons: [
                {text: _t("Close"), click: function() { self.stop(); }},
                {text: _t("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.delegate('fieldset legend', 'click', function() {
            $(this).parent().toggleClass('oe-closed');
        });
        this.ready.push(new openerp.web.DataSet(this, this.model).call(
            'fields_get', [], function (fields) {
                self.graft_fields(fields);
                self.ready.push(new openerp.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':
                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.$element.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['error']) {
            result_node.append(QWeb.render('ImportView.error', {
                'error': results['error']}));
            this.$element.find('fieldset').removeClass('oe-closed');
            return;
        }
        if (results['success']) {
            if (this.widget_parent.widget_parent.active_view == "list") {
                this.widget_parent.reload_content();
            }
            this.stop();
            return;
        }

        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
            }));
            this.$element.find('fieldset').addClass('oe-closed');
        }
        this.$element.find('form').removeClass('oe-import-no-result');

        this.$element.delegate('.oe-m2o-drop-down-button', 'click', function () {
            $(this).prev('input').focus();
        });

        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 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) {
            // TODO: levenshtein between header and field.string
            return field.name === name
                || 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
                || 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.$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 = $('
'+_t("Destination fields should only be selected once, some fields are selected more than once:")+'
').insertBefore(this.$element.find('#result'));
            var $dupes = $('
').appendTo($err);
            _(duplicates).each(function(elements, value) {
                $('
').text(value).appendTo($dupes);
                _(elements).each(function(element) {
                    var cell = $(element).closest('td');
                    $('
').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('
' + _t("*Required Fields are not selected :") + missing_fields + '.
');
            return false;
        }
        return true;
    },
    stop: function() {
        this.$element.remove();
        this._super();
    }
});
};
<commit_msg>[FIX] data_import: allow importing m2o via name_search() on top of their XML ID<commit_after>openerp.web.data_import = function(openerp) {
var QWeb = openerp.web.qweb,
    _t = openerp.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);
}

openerp.web.DataImport = openerp.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('name')
                .value();
            convert_fields(self);
            self.all_fields.sort();
        });
    },
    start: function() {
        var self = this;
        this._super();
        this.open({
            buttons: [
                {text: _t("Close"), click: function() { self.stop(); }},
                {text: _t("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.delegate('fieldset legend', 'click', function() {
            $(this).parent().toggleClass('oe-closed');
        });
        this.ready.push(new openerp.web.DataSet(this, this.model).call(
            'fields_get', [], function (fields) {
                self.graft_fields(fields);
                self.ready.push(new openerp.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 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.$element.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['error']) {
            result_node.append(QWeb.render('ImportView.error', {
                'error': results['error']}));
            this.$element.find('fieldset').removeClass('oe-closed');
            return;
        }
        if (results['success']) {
            if (this.widget_parent.widget_parent.active_view == "list") {
                this.widget_parent.reload_content();
            }
            this.stop();
            return;
        }

        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
            }));
            this.$element.find('fieldset').addClass('oe-closed');
        }
        this.$element.find('form').removeClass('oe-import-no-result');

        this.$element.delegate('.oe-m2o-drop-down-button', 'click', function () {
            $(this).prev('input').focus();
        });

        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 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) {
            // TODO: levenshtein between header and field.string
            return field.name === name
                || 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
                || 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.$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 = $('
'+_t("Destination fields should only be selected once, some fields are selected more than once:")+'
').insertBefore(this.$element.find('#result'));
            var $dupes = $('
').appendTo($err);
            _(duplicates).each(function(elements, value) {
                $('
').text(value).appendTo($dupes);
                _(elements).each(function(element) {
                    var cell = $(element).closest('td');
                    $('
').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('
' + _t("*Required Fields are not selected :") + missing_fields + '.
');
            return false;
        }
        return true;
    },
    stop: function() {
        this.$element.remove();
        this._super();
    }
});
};
<|endoftext|>