mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 18:17:20 +00:00
81f07cdf85
* Use state.wiki * use local wiki where available * fix a couple this vs self cases
203 lines
6.2 KiB
JavaScript
203 lines
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;
|
|
|
|
})();
|