diff --git a/converter.js b/converter.js index a88d948..72d9da5 100644 --- a/converter.js +++ b/converter.js @@ -1,151 +1,215 @@ -excelParser = { - latexEscape: function(text) { - escapeRegExpr = function(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - }; +!(function($) { + "use strict"; - var specials = ['\\', '&', '%', '$', '#', '_', '{', '}', '~', '^']; - $.each(specials, function() { - var regexp = new RegExp(escapeRegExpr(this), 'g'); - text = text.replace(regexp, '\\' + this, 'g'); - }); + // Global variable with information on current workbooks. Don't judge me. + var workbooks = {}; - return text; - }, + // Another global to store LaTeX output. Don't judge me...again... + var latexOutput = {}; - parseStringTable: function(data) { - var doc = $(data); - var stringTags = doc.find('si'); - var strings = $.map(stringTags, function(s,i) { - return $(s).find('t').text(); - }); + var excelParser = { + latexEscape: function(text) { + var escapeRegExpr = function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }; - return strings; - }, + var specials = ['\\', '&', '%', '$', '#', '_', '{', '}', '~', '^']; + $.each(specials, function() { + var regexp = new RegExp(escapeRegExpr(this), 'g'); + text = text.replace(regexp, '\\' + this, 'g'); + }); - toLatex: function(table) { - var max = 0; - for(var i=0; i < table.length; i++) { - if(table[i] && table[i].length > max) { max = table[i].length; } - } + return text; + }, - var numCols = max; - var args = []; - for(var i=0; i < numCols; i++) { - args[i] = 'l'; - } - args = ' | ' + args.join(' | ') + ' | '; - var latex = "\\begin{tabular}{" + args + "}\n\\hline\n"; - for(var i=0; i < table.length; i++) { - var cols = table[i]; - // TODO: replace "&" with "\&" - if(cols === undefined) { cols = []; } - if(cols.length < numCols) { - for(var x=cols.length; x < max; x++) { - cols[x] = '\\ '; - } + parseStringTable: function(data) { + var doc = $(data); + var stringTags = doc.find('si'); + var strings = $.map(stringTags, function(s,i) { + return $(s).find('t').text(); + }); + + return strings; + }, + + toLatex: function(table) { + var max = 0; + for(var i=0; i < table.length; i++) { + if(table[i] && table[i].length > max) { max = table[i].length; } } - latex += "\t" + cols.join(' & '); - latex += " \\\\ \\hline\n"; - } - - latex += "\\end{tabular}\n"; - - $('#latex-output').val(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')); - - // 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; + var numCols = max; + var args = []; + for(i=0; i < numCols; i++) { + args[i] = 'l'; + } + args = ' | ' + args.join(' | ') + ' | '; + var latex = "\\begin{tabular}{" + args + "}\n\\hline\n"; + for(i=0; i < table.length; i++) { + var cols = table[i]; + // TODO: replace "&" with "\&" + if(cols === undefined) { cols = []; } + if(cols.length < numCols) { + for(var x=cols.length; x < max; x++) { + cols[x] = '\\ '; + } } + + 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) { - // filter out all files that aren't worksheets - var sheets = $.grep(entries, function(n,i) { - return (/^xl\/worksheets\/.*\.xml$/.test(n.filename)) && (!/^xl\/worksheets\/_rels/.test(n.filename)); - }); + handleSheets: function(entries, stringTable) { + // get the workbook.xml file, which contains the names of all workbooks + var workbookMeta = entries.filter(function(entry) { + return entry.filename === 'xl/workbook.xml'; + })[0]; - // for now, only process the first sheet - // TODO: give the user a choice of which sheet to process - var sheet = sheets[0]; - sheet.getData(new zip.TextWriter(), function(text) { - var table = excelParser.processSheet(text, stringTable); - excelParser.toLatex(table); - }); - }, + // filter out all files that aren't worksheets + var sheets = $.grep(entries, function(n,i) { + var filter1 = /^xl\/worksheets\/.*\.xml$/; + var filter2 = /^xl\/worksheets\/_rels/; + return (filter1.test(n.filename)) && (!filter2.test(n.filename)); + }); - handleFile: function(event) { - // prevent default browser behavior - event.stopPropagation(); - event.preventDefault(); - - // 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; - } - - 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); + // read the workbook meta data to get the names and crap + workbookMeta.getData(new zip.TextWriter(), function(text) { + var doc = $(text); + + // extract the names of the workbooks and their IDs for use later on... + $.each(doc.find('sheets sheet'), function(i, tag) { + tag = $(tag); + var id = tag.attr('sheetId'); + var name = tag.attr('name'); + workbooks[id] = name; }); + 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() { - // hack because of jQuery shenanigans - jQuery.event.props.push('dataTransfer'); - - $('body').bind('dragover', function(event) { + handleFiles: function(event) { + // prevent default browser behavior event.stopPropagation(); 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() { - zip.workerScriptsPath = 'zip/'; - excelParser.init(); -}); + 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) { + 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 = $(''); + 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); diff --git a/index.html b/index.html index aa4aed1..c72045a 100644 --- a/index.html +++ b/index.html @@ -25,6 +25,9 @@

excel => LaTeX

Drag any .xlsx file onto the page to extract data and convert it into a LaTeX table

+ + +

Mostly untested, so if you find a bug or have a feature request, let me know!

Note: this only works with .xlsx files. That means .xls files will not work.

@@ -32,7 +35,7 @@

Lovingly hacked together by Eric Wood

- +