1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 03:57:21 +00:00

Two improvements to xlsx-utils plugin

Add support for skipping an entire tiddler if a particular column is
blank

Add support for reading a row by column, making each of the columns
into a fieldname.

Also significantly refactored the code to break up the main, monolithic
function.
This commit is contained in:
Jermolene 2016-11-14 15:23:15 +00:00
parent f7d81a00c2
commit a485eb8588
4 changed files with 145 additions and 88 deletions

View File

@ -130,6 +130,8 @@ suffixed
<$reveal state="""$(field)$!!import-field-source""" type="match" text="constant" default="column" tag="span">
<$edit-text tiddler=<<field>> field="import-field-value" tag="input" placeholder="constant" default=""/>
</$reveal>
<$checkbox tiddler=<<field>> field="import-field-skip-tiddler-if-blank" checked="yes" unchecked="no" default="no">
Skip this tiddler when field blank
<br/>
Title:
<$tiddler tiddler=<<field>>>
@ -192,6 +194,13 @@ Title:
</$tiddler>
</li>
<li>
Row type:
<$select tiddler=<<row>> field="import-row-type" default="by-field">
<option value="by-field">By field</option>
<option value="by-column">By column</option>
</$select>
</li>
<li>
<$button class="tc-btn-invisible">
<$action-createtiddler $basetitle="$:/_ExcelImporter/ImportSpecifiers/Field" $savetitle="$:/temp/newtiddler" import-spec-role="field" import-field-name="fieldname" import-field-type="string" import-field-source="column" import-field-column="Column Name" />
<$action-listops $tiddler=<<row>> $subfilter="[{$:/temp/newtiddler}] +[putfirst[]]"/>

View File

@ -23,7 +23,7 @@ exports["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = f
text: text
});
// Return the output tiddlers
return importer.importTiddlers();
return importer.getResults();
};
})();

View File

@ -21,103 +21,151 @@ var XLSXImporter = function(options) {
this.filename = options.filename;
this.text = options.text;
this.importSpec = options.importSpec || $tw.wiki.getTiddlerText(DEFAULT_IMPORT_SPEC_TITLE);
this.logger = new $tw.utils.Logger("xlsx-utils");
this.results = [];
if(JSZip) {
this.processWorkbook();
}
};
XLSXImporter.prototype.importTiddlers = function() {
var self = this,
results = [],
workbook;
// Check for the JSZIP plugin
if(!JSZip) {
return results;
}
XLSXImporter.prototype.getResults = function() {
return this.results;
};
XLSXImporter.prototype.processWorkbook = function() {
// Read the workbook
if(this.filename) {
workbook = XLSX.readFile(this.filename);
this.workbook = XLSX.readFile(this.filename);
} else if(this.text) {
workbook = XLSX.read(this.text,{type:"base64"});
this.workbook = XLSX.read(this.text,{type:"base64"});
}
// Read the root import specification
var rootImportSpec = $tw.wiki.getTiddler(this.importSpec);
if(rootImportSpec) {
this.rootImportSpec = $tw.wiki.getTiddler(this.importSpec);
if(this.rootImportSpec) {
// Iterate through the sheets specified in the list field
$tw.utils.each(rootImportSpec.fields.list || [],function(sheetImportSpecTitle) {
// Get the sheet import specifier
var sheetImportSpec = $tw.wiki.getTiddler(sheetImportSpecTitle);
if(sheetImportSpec) {
var sheetName = sheetImportSpec.fields["import-sheet-name"],
sheet = workbook.Sheets[sheetName];
// Get the size of the sheet
var sheetSize = self.measureSheet(sheet);
// Read the column names from the first row
var columnsByName = self.findColumns(sheet,sheetSize);
// Iterate through the rows
for(var row=sheetSize.startRow+1; row<=sheetSize.endRow; row++) {
// Iterate through the row import specifiers
$tw.utils.each(sheetImportSpec.fields.list || [],function(rowImportSpecTitle) {
var rowImportSpec = $tw.wiki.getTiddler(rowImportSpecTitle);
if(rowImportSpec) {
var tiddlerFields = {};
// Iterate through the fields for the row
$tw.utils.each(rowImportSpec.fields.list || [],function(fieldImportSpecTitle) {
var fieldImportSpec = $tw.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 = sheet[XLSX.utils.encode_cell({c: columnsByName[columnName], r: 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;
}
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"];
}
if(fieldImportSpec.fields["import-field-replace-blank"] && (value || "").trim() === "") {
value = fieldImportSpec.fields["import-field-replace-blank"];
}
switch(fieldImportSpec.fields["import-field-list-op"] || "none") {
case "none":
tiddlerFields[fieldName] = value;
break;
case "append":
var list = $tw.utils.parseStringArray(tiddlerFields[fieldName] || "");
$tw.utils.pushTop(list,value)
tiddlerFields[fieldName] = list;
break;
}
}
});
results.push(tiddlerFields);
}
});
}
}
});
$tw.utils.each(this.rootImportSpec.fields.list || [],this.processSheet.bind(this));
}
return results;
};
XLSXImporter.prototype.processSheet = function(sheetImportSpecTitle) {
// Get the sheet import specifier
this.sheetImportSpec = $tw.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 = $tw.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;
}
});
};
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 = $tw.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;
}
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"];
}
if((value || "").trim() === "") {
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"];
}
}
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 {

View File

@ -36,7 +36,7 @@ Command.prototype.execute = function() {
filename: filename,
importSpec: importSpec
});
$tw.wiki.addTiddlers(importer.importTiddlers());
$tw.wiki.addTiddlers(importer.getResults());
return null;
};