keeweb/app/scripts/views/import-csv-view.js

189 lines
5.8 KiB
JavaScript
Raw Normal View History

2021-05-08 11:38:23 +02:00
import * as kdbxweb from 'kdbxweb';
2019-09-25 23:24:38 +02:00
import { View } from 'framework/views/view';
import { Scrollable } from 'framework/views/scrollable';
import template from 'templates/import-csv.hbs';
import { EntryModel } from 'models/entry-model';
class ImportCsvView extends View {
parent = '.app__body';
template = template;
events = {
'click .back-button': 'returnToApp',
'click .import-csv__button-cancel': 'returnToApp',
'click .import-csv__button-run': 'runImport',
2019-09-26 07:19:20 +02:00
'change .import-csv__field-select': 'changeMapping',
'change .import-csv__target-select': 'changeGroup'
2019-09-25 23:24:38 +02:00
};
knownFields = [
{ field: 'Title', re: /title|\bname|account/i },
{ field: 'UserName', re: /user|login/i },
{ field: 'Password', re: /pass/i },
{ field: 'URL', re: /url|site/i },
{ field: 'Notes', re: /notes|comment|extra/i }
];
fieldMapping = [];
2019-09-26 07:19:20 +02:00
targetGroup = undefined;
2019-09-25 23:24:38 +02:00
constructor(model, options) {
super(model, options);
this.appModel = options.appModel;
this.fileName = options.fileName;
2019-09-26 07:19:20 +02:00
this.guessFieldMapping();
this.fillGroups();
this.initScroll();
2019-09-25 23:24:38 +02:00
}
render() {
super.render({
headers: this.model.headers,
rows: this.model.rows,
2019-09-26 07:19:20 +02:00
fieldMapping: this.fieldMapping,
groups: this.groups
2019-09-25 23:24:38 +02:00
});
this.createScroll({
root: this.$el.find('.import-csv__body')[0],
scroller: this.$el.find('.import-csv__body > .scroller')[0],
bar: this.$el.find('.import-csv__body > .scroller__bar-wrapper > .scroller__bar')[0]
2019-09-25 23:24:38 +02:00
});
this.pageResized();
if (!this.scroll._update) {
this.scroll._update = this.scroll.update;
this.scroll.update = this.scrollUpdate.bind(this);
}
}
scrollUpdate() {
this.scroller.css({ width: 'auto', minWidth: 'auto', maxWidth: 'auto' });
this.scroll._update();
2019-09-25 23:24:38 +02:00
}
returnToApp() {
this.emit('cancel');
}
changeMapping(e) {
const col = +e.target.dataset.col;
const field = e.target.value;
2020-06-01 16:53:51 +02:00
const isBuiltIn = this.knownFields.some((f) => f.field === field);
2019-09-25 23:24:38 +02:00
const mapping = field ? (isBuiltIn ? 'builtin' : 'custom') : 'ignore';
this.fieldMapping[col] = {
mapping,
field
};
if (field) {
let ix = 0;
for (const mapping of this.fieldMapping) {
if (mapping.field === field && col !== ix) {
mapping.type = 'ignore';
mapping.field = '';
const select = this.el.querySelector(
`.import-csv__field-select[data-col="${ix}"]`
);
select.value = '';
}
ix++;
}
}
}
2019-09-26 07:19:20 +02:00
guessFieldMapping() {
2019-09-25 23:24:38 +02:00
const usedFields = {};
2020-06-01 16:53:51 +02:00
for (const fieldName of this.model.headers.map((f) => f.trim())) {
2019-09-25 23:24:38 +02:00
if (!fieldName || /^(group|grouping)$/i.test(fieldName)) {
this.fieldMapping.push({ type: 'ignore' });
continue;
}
let found = false;
for (const { field, re } of this.knownFields) {
if (!usedFields[field] && re.test(fieldName)) {
this.fieldMapping.push({ type: 'builtin', field });
usedFields[field] = true;
found = true;
break;
}
}
if (!found) {
this.fieldMapping.push({ type: 'custom', field: fieldName });
}
}
}
2019-09-26 07:19:20 +02:00
fillGroups() {
this.groups = [];
for (const file of this.appModel.files) {
2020-06-01 16:53:51 +02:00
file.forEachGroup((group) => {
2020-04-23 20:06:10 +02:00
const title = group.title;
const spaces = [];
2019-09-26 07:19:20 +02:00
for (let parent = group; parent.parentGroup; parent = parent.parentGroup) {
2020-04-23 20:06:10 +02:00
spaces.push(' ', ' ');
2019-09-26 07:19:20 +02:00
}
2020-04-23 20:06:10 +02:00
this.groups.push({ id: group.id, fileId: file.id, spaces, title });
2019-09-26 07:19:20 +02:00
});
}
}
changeGroup(e) {
const groupId = e.target.value;
if (!groupId) {
this.targetGroup = undefined;
return;
}
const fileId = e.target.querySelector(`option[value="${groupId}"]`).dataset.file;
const file = this.appModel.files.get(fileId);
this.targetGroup = file.getGroup(groupId);
}
2019-09-25 23:24:38 +02:00
runImport() {
2019-09-26 07:19:20 +02:00
let group = this.targetGroup;
let filePromise;
if (group) {
filePromise = Promise.resolve(group.file);
} else {
2019-09-26 07:19:20 +02:00
const fileName = this.fileName.replace(/\.csv$/i, '');
filePromise = new Promise((resolve) => this.appModel.createNewFile(fileName, resolve));
2019-09-26 07:19:20 +02:00
}
filePromise.then((file) => {
if (!group) {
group = file.groups[0];
}
for (const row of this.model.rows) {
const newEntry = EntryModel.newEntry(group, file);
for (let ix = 0; ix < row.length; ix++) {
let value = row[ix];
if (!value) {
continue;
}
const mapping = this.fieldMapping[ix];
if (mapping.type === 'ignore' || !mapping.field) {
continue;
}
if (mapping.field === 'Password') {
value = kdbxweb.ProtectedValue.fromString(value);
}
newEntry.setField(mapping.field, value);
2019-09-25 23:24:38 +02:00
}
}
file.reload();
this.emit('done');
});
2019-09-25 23:24:38 +02:00
}
}
Object.assign(ImportCsvView.prototype, Scrollable);
export { ImportCsvView };