diff --git a/Makefile b/Makefile index b34317b..2b4e0d2 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,8 @@ init: ## Initial setup for development git submodule init git submodule update #git submodule foreach git pull origin master - git submodule foreach make + #git submodule foreach make + git submodule foreach make all mkdir -p tmp DISTHDR=misc/suppress_export.js diff --git a/bits/00_header.js b/bits/00_header.js index ead5056..acd0919 100644 --- a/bits/00_header.js +++ b/bits/00_header.js @@ -1,6 +1,6 @@ /*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */ /* vim: set ts=2: */ /*exported XLSX */ -/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ +/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, Deno:false */ var XLSX = {}; function make_xlsx_lib(XLSX){ diff --git a/bits/40_harb.js b/bits/40_harb.js index 980ba1d..2d8e0d8 100644 --- a/bits/40_harb.js +++ b/bits/40_harb.js @@ -204,7 +204,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break; case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break; - case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break; + case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4 + (dd.read_shift(4, 'i')/1e4)*Math.pow(2,32); break; case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break; case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; } /* falls through */ @@ -218,13 +218,20 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { } if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows); + opts.DBF = fields; return out; } function dbf_to_sheet(buf, opts)/*:Worksheet*/ { var o = opts || {}; if(!o.dateNF) o.dateNF = "yyyymmdd"; - return aoa_to_sheet(dbf_to_aoa(buf, o), o); + var ws = aoa_to_sheet(dbf_to_aoa(buf, o), o); + ws["!cols"] = o.DBF.map(function(field) { return { + wch: field.len, + DBF: field + }}); + delete o.DBF; + return ws; } function dbf_to_workbook(buf, opts)/*:Workbook*/ { @@ -240,10 +247,11 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { if(o.type == "string") throw new Error("Cannot write DBF to JS string"); var ba = buf_array(); var aoa/*:AOA*/ = sheet_to_json(ws, {header:1, raw:true, cellDates:true}); - var headers = aoa[0], data = aoa.slice(1); + var headers = aoa[0], data = aoa.slice(1), cols = ws["!cols"] || []; var i = 0, j = 0, hcnt = 0, rlen = 1; for(i = 0; i < headers.length; ++i) { - if(i == null) continue; + if(((cols[i]||{}).DBF||{}).name) { headers[i] = cols[i].DBF.name; ++hcnt; continue; } + if(headers[i] == null) continue; ++hcnt; if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10); if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|"); @@ -252,13 +260,15 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { } var range = safe_decode_range(ws['!ref']); var coltypes/*:Array*/ = []; + var colwidths/*:Array*/ = []; + var coldecimals/*:Array*/ = []; for(i = 0; i <= range.e.c - range.s.c; ++i) { + var guess = '', _guess = '', maxlen = 0; var col/*:Array*/ = []; for(j=0; j < data.length; ++j) { if(data[j][i] != null) col.push(data[j][i]); } if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; } - var guess = '', _guess = ''; for(j = 0; j < col.length; ++j) { switch(typeof col[j]) { /* TODO: check if L2 compat is desired */ @@ -268,10 +278,23 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break; default: _guess = 'C'; } + maxlen = Math.max(maxlen, String(col[j]).length); guess = guess && guess != _guess ? 'C' : _guess; - if(guess == 'C') break; + //if(guess == 'C') break; } - rlen += _RLEN[guess] || 0; + if(maxlen > 250) maxlen = 250; + _guess = ((cols[i]||{}).DBF||{}).type; + /* TODO: more fine grained control over DBF type resolution */ + if(_guess == 'C') { + if(cols[i].DBF.len > maxlen) maxlen = cols[i].DBF.len; + } + if(guess == 'B' && _guess == 'N') { + guess = 'N'; + coldecimals[i] = cols[i].DBF.dec; + maxlen = cols[i].DBF.len; + } + colwidths[i] = guess == 'C' || _guess == 'N' ? maxlen : (_RLEN[guess] || 0); + rlen += colwidths[i]; coltypes[i] = guess; } @@ -290,14 +313,14 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { hf.write_shift(1, _f, "sbcs"); hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs"); hf.write_shift(4, j); - hf.write_shift(1, _RLEN[coltypes[i]] || 0); - hf.write_shift(1, 0); + hf.write_shift(1, colwidths[i] || _RLEN[coltypes[i]] || 0); + hf.write_shift(1, coldecimals[i] || 0); hf.write_shift(1, 0x02); hf.write_shift(4, 0); hf.write_shift(1, 0); hf.write_shift(4, 0); hf.write_shift(4, 0); - j += _RLEN[coltypes[i]] || 0; + j += (colwidths[i] || _RLEN[coltypes[i]] || 0); } var hb = ba.next(264); @@ -311,6 +334,12 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { switch(coltypes[j]) { case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break; case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break; + case 'N': + var _n = "0"; + if(typeof data[i][j] == "number") _n = data[i][j].toFixed(coldecimals[j]||0); + for(hcnt=0; hcnt < colwidths[j]-_n.length; ++hcnt) rout.write_shift(1, 0x20); + rout.write_shift(1, _n, "sbcs"); + break; case 'D': if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs"); else { @@ -319,9 +348,9 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs"); } break; case 'C': - var _s = String(data[i][j]||""); + var _s = String(data[i][j] != null ? data[i][j] : "").slice(0, colwidths[j]); rout.write_shift(1, _s, "sbcs"); - for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break; + for(hcnt=0; hcnt < colwidths[j]-_s.length; ++hcnt) rout.write_shift(1, 0x20); break; } } // data diff --git a/bits/83_numbers.js b/bits/83_numbers.js index bce2b68..48a6637 100644 --- a/bits/83_numbers.js +++ b/bits/83_numbers.js @@ -442,13 +442,14 @@ var NUMBERS = !Object.defineProperty ? (void 0) :(function() { return { Sheets: {}, SheetNames: [] }; }; var book_append_sheet = function(wb, ws, name) { + var i = 1; if (!name) - for (var i = 1; i < 9999; ++i) { + for (; i < 9999; ++i) { if (wb.SheetNames.indexOf(name = "Sheet ".concat(i)) == -1) break; } else if (wb.SheetNames.indexOf(name) > -1) - for (var i = 1; i < 9999; ++i) { + for (; i < 9999; ++i) { if (wb.SheetNames.indexOf("".concat(name, "_").concat(i)) == -1) { name = "".concat(name, "_").concat(i); break; diff --git a/bits/90_utils.js b/bits/90_utils.js index 3e633b8..06fac10 100644 --- a/bits/90_utils.js +++ b/bits/90_utils.js @@ -64,7 +64,8 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { var out/*:Array*/ = []; var outi = 0, counter = 0; var dense = Array.isArray(sheet); - var R = r.s.r, C = 0, CC = 0; + var R = r.s.r, C = 0; + var header_cnt = {}; if(dense && !sheet[R]) sheet[R] = []; for(C = r.s.c; C <= r.e.c; ++C) { cols[C] = encode_col(C); @@ -76,8 +77,12 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) { default: if(val == null) val = {w: "__EMPTY", t: "s"}; vv = v = format_cell(val, null, o); - counter = 0; - for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) { vv = v + "_" + (++counter); CC = -1; } + counter = header_cnt[v] || 0; + if(!counter) header_cnt[v] = 1; + else { + do { vv = v + "_" + (counter++); } while(header_cnt[vv]); header_cnt[v] = counter; + header_cnt[vv] = 1; + } hdr[C] = vv; } } diff --git a/bits/97_node.js b/bits/97_node.js index f57e001..8fc2819 100644 --- a/bits/97_node.js +++ b/bits/97_node.js @@ -79,7 +79,8 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { var cols/*:Array*/ = []; var counter = 0; var dense = Array.isArray(sheet); - var R = r.s.r, C = 0, CC = 0; + var R = r.s.r, C = 0; + var header_cnt = {}; if(dense && !sheet[R]) sheet[R] = []; for(C = r.s.c; C <= r.e.c; ++C) { cols[C] = encode_col(C); @@ -91,8 +92,12 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { default: if(val == null) val = {w: "__EMPTY", t: "s"}; vv = v = format_cell(val, null, o); - counter = 0; - for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter); + counter = header_cnt[v] || 0; + if(!counter) header_cnt[v] = 1; + else { + do { vv = v + "_" + (counter++); } while(header_cnt[vv]); header_cnt[v] = counter; + header_cnt[vv] = 1; + } hdr[C] = vv; } } @@ -110,7 +115,7 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { return stream.push(null); }; return stream; -}; +} var __stream = { to_json: write_json_stream, diff --git a/demos/vue/Makefile b/demos/vue/Makefile index 70db57f..a47d6d3 100644 --- a/demos/vue/Makefile +++ b/demos/vue/Makefile @@ -4,9 +4,7 @@ vue: ## Simple server for vue .PHONY: nuxt nuxt: ## nuxt.js demo - mkdir -p node_modules - cd node_modules; if [ ! -e xlsx ]; then ln -s ../../../ xlsx; fi; cd .. - npm i nuxt vue + npm i xlsx @nuxt/content npx nuxt .PHONY: weex diff --git a/demos/vue/README.md b/demos/vue/README.md index 78c90fe..2c01b18 100644 --- a/demos/vue/README.md +++ b/demos/vue/README.md @@ -1,4 +1,4 @@ -# VueJS 2 +# VueJS The `xlsx.core.min.js` and `xlsx.full.min.js` scripts are designed to be dropped into web pages with script tags: @@ -10,7 +10,11 @@ into web pages with script tags: The library can also be imported directly from single-file components with: ```js -import XLSX from 'xlsx'; +// full import +import * as XLSX from 'xlsx'; + +// named imports +import { read, utils, writeFileXLSX } from 'xlsx'; ``` This demo directly generates HTML using `sheet_to_html` and adds an element to @@ -93,19 +97,30 @@ fs.writeFileSync("sheetjs.xls", new Buffer(str, "base64")); ## Other Demos -#### Server-Rendered VueJS Components with Nuxt.js +### Nuxt Content -The scripts should be treated as external resources in `nuxt.config.js`: +`@nuxt/content` parser can be extended to support spreadsheet hot reload: ```js -module.exports = { - head: { - script: [ - { src: "https://unpkg.com/xlsx/dist/shim.min.js" }, - { src: "https://unpkg.com/xlsx/dist/xlsx.full.min.js" } - ] - } -}; +// nuxt.config.js +import { readFile, utils } from 'xlsx'; + +const parseXLSX = (file, { path }) => { + const wb = readFile(path); + const o = wb.SheetNames.map(name => ({ name, data: utils.sheet_to_json(wb.Sheets[name])})); + return { data: o }; +} + +export default { + content: { + extendParser: { + ".numbers": parseXLSX, + ".xlsx": parseXLSX, + ".xls": parseXLSX + // ... other extensions + } + } +} ``` [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/vue/content/sheetjs.numbers b/demos/vue/content/sheetjs.numbers new file mode 100755 index 0000000..700e97d Binary files /dev/null and b/demos/vue/content/sheetjs.numbers differ diff --git a/demos/vue/native.vue b/demos/vue/native.vue index 1dcea82..5588eed 100644 --- a/demos/vue/native.vue +++ b/demos/vue/native.vue @@ -27,7 +27,7 @@ diff --git a/demos/xhr/axios.html b/demos/xhr/axios.html index 30deb81..7a492be 100644 --- a/demos/xhr/axios.html +++ b/demos/xhr/axios.html @@ -26,21 +26,33 @@ a { text-decoration: none } - +