tabulator-tables
Version:
Interactive table generation JavaScript library
303 lines (232 loc) • 6.69 kB
JavaScript
import Module from '../../core/Module.js';
import defaultImporters from './defaults/importers.js';
export default class Import extends Module{
static moduleName = "import";
//load defaults
static importers = defaultImporters;
constructor(table){
super(table);
this.registerTableOption("importFormat");
this.registerTableOption("importReader", "text");
this.registerTableOption("importHeaderTransform");
this.registerTableOption("importValueTransform");
this.registerTableOption("importDataValidator");
this.registerTableOption("importFileValidator");
}
initialize(){
this.registerTableFunction("import", this.importFromFile.bind(this));
if(this.table.options.importFormat){
this.subscribe("data-loading", this.loadDataCheck.bind(this), 10);
this.subscribe("data-load", this.loadData.bind(this), 10);
}
}
loadDataCheck(data){
return this.table.options.importFormat && (typeof data === "string" || (Array.isArray(data) && data.length && Array.isArray(data)));
}
loadData(data, params, config, silent, previousData){
return this.importData(this.lookupImporter(), data)
.then(this.structureData.bind(this))
.catch((err) => {
console.error("Import Error:", err || "Unable to import data");
return Promise.reject(err);
});
}
lookupImporter(importFormat){
var importer;
if(!importFormat){
importFormat = this.table.options.importFormat;
}
if(typeof importFormat === "string"){
importer = Import.importers[importFormat];
}else{
importer = importFormat;
}
if(!importer){
console.error("Import Error - Importer not found:", importFormat);
}
return importer;
}
importFromFile(importFormat, extension, importReader){
var importer = this.lookupImporter(importFormat);
if(importer){
return this.pickFile(extension, importReader)
.then(this.importData.bind(this, importer))
.then(this.structureData.bind(this))
.then(this.mutateData.bind(this))
.then(this.validateData.bind(this))
.then(this.setData.bind(this))
.catch((err) => {
this.dispatch("import-error", err);
this.dispatchExternal("importError", err);
console.error("Import Error:", err || "Unable to import file");
this.table.dataLoader.alertError();
setTimeout(() => {
this.table.dataLoader.clearAlert();
}, 3000);
return Promise.reject(err);
});
}
}
pickFile(extensions, importReader){
return new Promise((resolve, reject) => {
var input = document.createElement("input");
input.type = "file";
input.accept = extensions;
input.addEventListener("change", (e) => {
var file = input.files[0],
reader = new FileReader(),
valid = this.validateFile(file);
if(valid === true){
this.dispatch("import-importing", input.files);
this.dispatchExternal("importImporting", input.files);
switch(importReader || this.table.options.importReader){
case "buffer":
reader.readAsArrayBuffer(file);
break;
case "binary":
reader.readAsBinaryString(file);
break;
case "url":
reader.readAsDataURL(file);
break;
case "text":
default:
reader.readAsText(file);
}
reader.onload = (e) => {
resolve(reader.result);
};
reader.onerror = (e) => {
console.warn("File Load Error - Unable to read file");
reject(e);
};
}else{
reject(valid);
}
});
this.dispatch("import-choose");
this.dispatchExternal("importChoose");
input.click();
});
}
importData(importer, fileContents){
var data;
this.table.dataLoader.alertLoader();
return new Promise((resolve, reject) => {
setTimeout(() => {
data = importer.call(this.table, fileContents);
if(data instanceof Promise){
resolve(data);
}else{
data ? resolve(data) : reject();
}
}, 10);
});
}
structureData(parsedData){
var data = [];
if(Array.isArray(parsedData) && parsedData.length && Array.isArray(parsedData[0])){
if(this.table.options.autoColumns){
data = this.structureArrayToObject(parsedData);
}else{
data = this.structureArrayToColumns(parsedData);
}
return data;
}else{
return parsedData;
}
}
mutateData(data){
var output = [];
if(Array.isArray(data)){
data.forEach((row) => {
output.push(this.table.modules.mutator.transformRow(row, "import"));
});
}else{
output = data;
}
return output;
}
transformHeader(headers){
var output = [];
if(this.table.options.importHeaderTransform){
headers.forEach((item) => {
output.push(this.table.options.importHeaderTransform.call(this.table, item, headers));
});
}else{
return headers;
}
return output;
}
transformData(row){
var output = [];
if(this.table.options.importValueTransform){
row.forEach((item) => {
output.push(this.table.options.importValueTransform.call(this.table, item, row));
});
}else{
return row;
}
return output;
}
structureArrayToObject(parsedData){
var columns = this.transformHeader(parsedData.shift());
var data = parsedData.map((values) => {
var row = {};
values = this.transformData(values);
columns.forEach((key, i) => {
row[key] = values[i];
});
return row;
});
return data;
}
structureArrayToColumns(parsedData){
var data = [],
firstRow = this.transformHeader(parsedData[0]),
columns = this.table.getColumns();
//remove first row if it is the column names
if(columns[0] && firstRow[0]){
if(columns[0].getDefinition().title === firstRow[0]){
parsedData.shift();
}
}
//convert row arrays to objects
parsedData.forEach((rowData) => {
var row = {};
rowData = this.transformData(rowData);
rowData.forEach((value, index) => {
var column = columns[index];
if(column){
row[column.getField()] = value;
}
});
data.push(row);
});
return data;
}
validateFile(file){
if(this.table.options.importFileValidator){
return this.table.options.importFileValidator.call(this.table, file);
}
return true;
}
validateData(data){
var result;
if(this.table.options.importDataValidator){
result = this.table.options.importDataValidator.call(this.table, data);
if(result === true){
return data;
}else{
return Promise.reject(result);
}
}
return data;
}
setData(data){
this.dispatch("import-imported", data);
this.dispatchExternal("importImported", data);
this.table.dataLoader.clearAlert();
return this.table.setData(data);
}
}