TiddlyWiki5/plugins/tiddlywiki/xlsx-utils/importer.js

203 wiersze
6.2 KiB
JavaScript

/*\
title: $:/plugins/tiddlywiki/xlsx-utils/importer.js
type: application/javascript
module-type: library
Class to import an Excel file
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var DEFAULT_IMPORT_SPEC_TITLE = "$:/config/plugins/tiddlywiki/xlsx-utils/default-import-spec";
var XLSX = require("$:/plugins/tiddlywiki/xlsx-utils/xlsx.js"),
JSZip = require("$:/plugins/tiddlywiki/jszip/jszip.js");
var XLSXImporter = function(options) {
this.wiki = options.wiki;
this.filename = options.filename;
this.text = options.text;
this.importSpec = options.importSpec || this.wiki.getTiddlerText(DEFAULT_IMPORT_SPEC_TITLE);
this.logger = new $tw.utils.Logger("xlsx-utils");
this.results = [];
if(JSZip) {
this.processWorkbook();
}
};
XLSXImporter.prototype.getResults = function() {
return this.results;
};
XLSXImporter.prototype.processWorkbook = function() {
// Read the workbook
if(this.filename) {
this.workbook = XLSX.readFile(this.filename);
} else if(this.text) {
this.workbook = XLSX.read(this.text,{type:"base64"});
}
// Read the root import specification
this.rootImportSpec = this.wiki.getTiddler(this.importSpec);
if(this.rootImportSpec) {
// Iterate through the sheets specified in the list field
$tw.utils.each(this.rootImportSpec.fields.list || [],this.processSheet.bind(this));
}
};
XLSXImporter.prototype.processSheet = function(sheetImportSpecTitle) {
// Get the sheet import specifier
this.sheetImportSpec = this.wiki.getTiddler(sheetImportSpecTitle);
if(this.sheetImportSpec) {
this.sheetName = this.sheetImportSpec.fields["import-sheet-name"];
this.sheet = this.workbook.Sheets[this.sheetName];
if(!this.sheet) {
this.logger.alert("Missing sheet '" + this.sheetName + "'");
} else {
// Get the size of the sheet
this.sheetSize = this.measureSheet(this.sheet);
// Read the column names from the first row
this.columnsByName = this.findColumns(this.sheet,this.sheetSize);
// Iterate through the rows
for(this.row=this.sheetSize.startRow+1; this.row<=this.sheetSize.endRow; this.row++) {
// Iterate through the row import specifiers
$tw.utils.each(this.sheetImportSpec.fields.list || [],this.processRow.bind(this));
}
}
}
};
XLSXImporter.prototype.processRow = function(rowImportSpecTitle) {
this.rowImportSpec = this.wiki.getTiddler(rowImportSpecTitle);
if(this.rowImportSpec) {
this.tiddlerFields = {};
this.skipTiddler = false;
// Determine the type of row
this.rowType = this.rowImportSpec.fields["import-row-type"] || "by-field";
switch(this.rowType) {
case "by-column":
this.processRowByColumn();
break;
case "by-field":
this.processRowByField();
break;
}
// Save the tiddler if not skipped
if(!this.skipTiddler) {
if(!this.tiddlerFields.title) {
this.logger.alert("Missing title field for " + JSON.stringify(this.tiddlerFields));
}
this.results.push(this.tiddlerFields);
}
}
};
XLSXImporter.prototype.processRowByColumn = function() {
var self = this;
// Iterate through the columns for the row
$tw.utils.each(this.columnsByName,function(index,name) {
var cell = self.sheet[XLSX.utils.encode_cell({c: self.columnsByName[name], r: self.row})];
name = name.toLowerCase();
if(cell && cell.w && $tw.utils.isValidFieldName(name)) {
self.tiddlerFields[name] = cell.w;
}
});
// Skip the tiddler entirely if it doesn't have a title
if(!this.tiddlerFields.title) {
this.skipTiddler = true;
}
};
XLSXImporter.prototype.processRowByField = function() {
// Iterate through the fields for the row
$tw.utils.each(this.rowImportSpec.fields.list || [],this.processField.bind(this));
};
XLSXImporter.prototype.processField = function(fieldImportSpecTitle) {
var fieldImportSpec = this.wiki.getTiddler(fieldImportSpecTitle);
if(fieldImportSpec) {
var fieldName = fieldImportSpec.fields["import-field-name"],
value;
switch(fieldImportSpec.fields["import-field-source"]) {
case "column":
var columnName = fieldImportSpec.fields["import-field-column"],
cell = this.sheet[XLSX.utils.encode_cell({c: this.columnsByName[columnName], r: this.row})];
if(cell) {
switch(fieldImportSpec.fields["import-field-type"] || "string") {
case "date":
if(cell.t === "n") {
value = $tw.utils.stringifyDate(new Date((cell.v - (25567 + 2)) * 86400 * 1000));
}
break;
case "string":
// Intentional fall-through
default:
value = cell.w;
break;
}
}
break;
case "constant":
value = fieldImportSpec.fields["import-field-value"]
break;
}
value = (value || "").trim();
if(value === "") {
if((fieldImportSpec.fields["import-field-skip-tiddler-if-blank"] || "").trim().toLowerCase() === "yes") {
this.skipTiddler = true;
}
if(fieldImportSpec.fields["import-field-replace-blank"]) {
value = fieldImportSpec.fields["import-field-replace-blank"];
}
}
if(fieldImportSpec.fields["import-field-prefix"]) {
value = fieldImportSpec.fields["import-field-prefix"] + value;
}
if(fieldImportSpec.fields["import-field-suffix"]) {
value = value + fieldImportSpec.fields["import-field-suffix"];
}
switch(fieldImportSpec.fields["import-field-list-op"] || "none") {
case "none":
this.tiddlerFields[fieldName] = value;
break;
case "append":
var list = $tw.utils.parseStringArray(this.tiddlerFields[fieldName] || "");
$tw.utils.pushTop(list,value)
this.tiddlerFields[fieldName] = list;
break;
}
}
}
XLSXImporter.prototype.measureSheet = function(sheet) {
var sheetRange = XLSX.utils.decode_range(sheet["!ref"]);
return {
startRow: Math.min(sheetRange.s.r,sheetRange.e.r),
endRow: Math.max(sheetRange.s.r,sheetRange.e.r),
startCol: Math.min(sheetRange.s.c,sheetRange.e.c),
endCol: Math.max(sheetRange.s.c,sheetRange.e.c)
}
};
XLSXImporter.prototype.findColumns = function(sheet,sheetSize) {
var columnsByName = {};
for(var col=sheetSize.startCol; col<=sheetSize.endCol; col++) {
var cell = sheet[XLSX.utils.encode_cell({c: col, r: sheetSize.startRow})],
columnName;
if(cell) {
columnName = cell.w;
if(columnName) {
columnsByName[columnName] = col;
}
}
}
return columnsByName;
};
exports.XLSXImporter = XLSXImporter;
})();