Ability to select workbooks. Fixes #4

This commit is contained in:
Eric Wood 2013-08-24 16:24:03 -05:00
parent bd6fd498aa
commit c5b4fa8f40
2 changed files with 197 additions and 130 deletions

View File

@ -1,151 +1,215 @@
excelParser = { !(function($) {
latexEscape: function(text) { "use strict";
escapeRegExpr = function(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
};
var specials = ['\\', '&', '%', '$', '#', '_', '{', '}', '~', '^']; // Global variable with information on current workbooks. Don't judge me.
$.each(specials, function() { var workbooks = {};
var regexp = new RegExp(escapeRegExpr(this), 'g');
text = text.replace(regexp, '\\' + this, 'g');
});
return text; // Another global to store LaTeX output. Don't judge me...again...
}, var latexOutput = {};
parseStringTable: function(data) { var excelParser = {
var doc = $(data); latexEscape: function(text) {
var stringTags = doc.find('si'); var escapeRegExpr = function(str) {
var strings = $.map(stringTags, function(s,i) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
return $(s).find('t').text(); };
});
return strings; var specials = ['\\', '&', '%', '$', '#', '_', '{', '}', '~', '^'];
}, $.each(specials, function() {
var regexp = new RegExp(escapeRegExpr(this), 'g');
text = text.replace(regexp, '\\' + this, 'g');
});
toLatex: function(table) { return text;
var max = 0; },
for(var i=0; i < table.length; i++) {
if(table[i] && table[i].length > max) { max = table[i].length; }
}
var numCols = max; parseStringTable: function(data) {
var args = []; var doc = $(data);
for(var i=0; i < numCols; i++) { var stringTags = doc.find('si');
args[i] = 'l'; var strings = $.map(stringTags, function(s,i) {
} return $(s).find('t').text();
args = ' | ' + args.join(' | ') + ' | '; });
var latex = "\\begin{tabular}{" + args + "}\n\\hline\n";
for(var i=0; i < table.length; i++) { return strings;
var cols = table[i]; },
// TODO: replace "&" with "\&"
if(cols === undefined) { cols = []; } toLatex: function(table) {
if(cols.length < numCols) { var max = 0;
for(var x=cols.length; x < max; x++) { for(var i=0; i < table.length; i++) {
cols[x] = '\\ '; if(table[i] && table[i].length > max) { max = table[i].length; }
}
} }
latex += "\t" + cols.join(' & '); var numCols = max;
latex += " \\\\ \\hline\n"; var args = [];
} for(i=0; i < numCols; i++) {
args[i] = 'l';
latex += "\\end{tabular}\n"; }
args = ' | ' + args.join(' | ') + ' | ';
$('#latex-output').val(latex); var latex = "\\begin{tabular}{" + args + "}\n\\hline\n";
}, for(i=0; i < table.length; i++) {
var cols = table[i];
processSheet: function(data, stringTable) { // TODO: replace "&" with "\&"
// get jQuery object out of the data for accessing stuffs if(cols === undefined) { cols = []; }
var doc = $(data); if(cols.length < numCols) {
for(var x=cols.length; x < max; x++) {
var table = []; cols[x] = '\\ ';
}
var rows = doc.find('sheetdata row');
$.each(rows, function(i,row) {
var rowNum = parseInt($(row).attr('r'));
// get columns
var cols = $(row).find('c');
var colVals = $.map(cols, function(col,j) {
var col = $(col);
var val = excelParser.latexEscape(col.find('v').text());
if(col.attr('t') == 's') {
return excelParser.latexEscape(stringTable[parseInt(val)]);
} else {
return val;
} }
latex += "\t" + cols.join(' & ');
latex += " \\\\ \\hline\n";
}
latex += "\\end{tabular}\n";
return latex;
},
processSheet: function(data, stringTable) {
// get jQuery object out of the data for accessing stuffs
var doc = $(data);
var table = [];
var rows = doc.find('sheetdata row');
$.each(rows, function(i,row) {
var rowNum = parseInt($(row).attr('r'), 10);
// get columns
var cols = $(row).find('c');
var colVals = $.map(cols, function(col,j) {
col = $(col);
var val = excelParser.latexEscape(col.find('v').text());
if(col.attr('t') == 's') {
return excelParser.latexEscape(stringTable[parseInt(val, 10)]);
} else {
return val;
}
});
table[rowNum-1] = colVals;
}); });
table[rowNum-1] = colVals;
});
return table; return table;
}, },
handleSheet: function(entries, stringTable) { handleSheets: function(entries, stringTable) {
// filter out all files that aren't worksheets // get the workbook.xml file, which contains the names of all workbooks
var sheets = $.grep(entries, function(n,i) { var workbookMeta = entries.filter(function(entry) {
return (/^xl\/worksheets\/.*\.xml$/.test(n.filename)) && (!/^xl\/worksheets\/_rels/.test(n.filename)); return entry.filename === 'xl/workbook.xml';
}); })[0];
// for now, only process the first sheet // filter out all files that aren't worksheets
// TODO: give the user a choice of which sheet to process var sheets = $.grep(entries, function(n,i) {
var sheet = sheets[0]; var filter1 = /^xl\/worksheets\/.*\.xml$/;
sheet.getData(new zip.TextWriter(), function(text) { var filter2 = /^xl\/worksheets\/_rels/;
var table = excelParser.processSheet(text, stringTable); return (filter1.test(n.filename)) && (!filter2.test(n.filename));
excelParser.toLatex(table); });
});
},
handleFile: function(event) { // read the workbook meta data to get the names and crap
// prevent default browser behavior workbookMeta.getData(new zip.TextWriter(), function(text) {
event.stopPropagation(); var doc = $(text);
event.preventDefault();
// extract the names of the workbooks and their IDs for use later on...
// get file information $.each(doc.find('sheets sheet'), function(i, tag) {
var files = event.dataTransfer.files; tag = $(tag);
if(!files.length) { var id = tag.attr('sheetId');
// no files were given somehow... var name = tag.attr('name');
$('#latex-output').val('No files were given...try again?'); workbooks[id] = name;
return false;
}
var blob = files[0];
// unzip and process files
zip.createReader(new zip.BlobReader(blob), function(reader) {
reader.getEntries(function(entries) {
if(!entries.length) { return false; }
// get the string table
var stFile = $.grep(entries, function(n,i) {
return /^xl\/sharedStrings\.xml$/.test(n.filename);
})[0];
stFile.getData(new zip.TextWriter(), function(text) {
var stringTable = excelParser.parseStringTable(text);
excelParser.handleSheet(entries, stringTable);
}); });
excelParser.updateSelect();
// iterate over all sheets and convert them to LaTeX
$.each(sheets, function(_, sheet) {
// the ID of the spreadsheet can only be found in the filename apparently :P
var id = sheet.filename.match(/(\d)\.xml/)[1];
sheet.getData(new zip.TextWriter(), function(text) {
var table = excelParser.processSheet(text, stringTable);
var latex = excelParser.toLatex(table);
latexOutput[id] = latex;
// I apologize for the hack :(
if(id === '1') {
$('#latex-output').val(latex);
}
});
});
}); });
}); },
},
init: function() { handleFiles: function(event) {
// hack because of jQuery shenanigans // prevent default browser behavior
jQuery.event.props.push('dataTransfer');
$('body').bind('dragover', function(event) {
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
});
$('body').bind('drop', excelParser.handleFile); // get file information
} var files = event.dataTransfer.files;
}; if(!files.length) {
// no files were given somehow...
$('#latex-output').val('No files were given...try again?');
return false;
}
$(function() { var blob = files[0];
zip.workerScriptsPath = 'zip/';
excelParser.init(); // unzip and process files
}); zip.createReader(new zip.BlobReader(blob), function(reader) {
reader.getEntries(function(entries) {
if(!entries.length) { return false; }
// get the string table
var stFile = $.grep(entries, function(n,i) {
var regexp = /^xl\/sharedStrings\.xml$/;
return regexp.test(n.filename);
})[0];
stFile.getData(new zip.TextWriter(), function(text) {
var stringTable = excelParser.parseStringTable(text);
excelParser.handleSheets(entries, stringTable);
});
return undefined;
});
});
return undefined;
},
updateSelect: function() {
var select = $('#workbook');
// clear existing option tags
select.empty();
for(var id in workbooks) {
var tag = $('<option value="' + id + '">' + workbooks[id] + '</option>');
tag.appendTo(select);
}
},
init: function() {
// hack because of jQuery shenanigans
jQuery.event.props.push('dataTransfer');
$('body').bind('dragover', function(event) {
event.stopPropagation();
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
});
$('body').bind('drop', excelParser.handleFiles);
// when a new workbook is selected, do stuff!
$('#workbook').change(function(event) {
var select = $(event.target);
var output = latexOutput[select.val()];
$('#latex-output').val(output);
});
}
};
$(function() {
zip.workerScriptsPath = 'zip/';
excelParser.init();
});
})(window.jQuery);

View File

@ -25,6 +25,9 @@
<h1 class="title">excel => LaTeX</h1> <h1 class="title">excel => LaTeX</h1>
<h4 class="info">Drag any .xlsx file onto the page to extract data and convert it into a LaTeX table</h4> <h4 class="info">Drag any .xlsx file onto the page to extract data and convert it into a LaTeX table</h4>
<div class="content"> <div class="content">
<label for="workbook">Workbook:</label>
<select id="workbook" name="workbook"></select>
<textarea id="latex-output" readonly="readonly"></textarea> <textarea id="latex-output" readonly="readonly"></textarea>
<p>Mostly untested, so if you find a bug or have a feature request, <a href="https://github.com/eric-wood/excel2latex/issues">let me know!</a> <p>Mostly untested, so if you find a bug or have a feature request, <a href="https://github.com/eric-wood/excel2latex/issues">let me know!</a>
<p class="disclaimer">Note: this only works with .xlsx files. That means .xls files will <b>not</b> work.</p> <p class="disclaimer">Note: this only works with .xlsx files. That means .xls files will <b>not</b> work.</p>
@ -32,7 +35,7 @@
<p>Lovingly hacked together by <a href="http://ericwood.org">Eric Wood</a></p> <p>Lovingly hacked together by <a href="http://ericwood.org">Eric Wood</a></p>
</div> </div>
</div> </div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="zip/zip.js"></script> <script type="text/javascript" src="zip/zip.js"></script>
<script type="text/javascript" src="converter.js"></script> <script type="text/javascript" src="converter.js"></script>
</body> </body>