From 54b528eaede80e86aec32fbbd268027b239b471a Mon Sep 17 00:00:00 2001 From: SheetJS Date: Thu, 9 Mar 2017 20:09:18 -0500 Subject: [PATCH] version bump 0.9.0: merged ODS into XLSX The optional ODS module has been completely merged into xlsx.js and the corresponding scripts have been removed. The new xlsx.js file provides appropriate ODS exports, so fixing is a matter of removing ods.js refs. --- .flowconfig | 4 +- .gitignore | 1 + CHANGELOG.md | 12 + Makefile | 25 +- README.md | 2 - bits/00_header.js | 1 + bits/01_version.js | 2 +- bits/20_jsutils.js | 27 + bits/21_ziputils.js | 1 + bits/22_xmlutils.js | 15 +- odsbits/30_manifest.js => bits/32_odmanrdf.js | 28 + odsbits/50_formula.js => bits/65_fods.js | 0 bits/67_wsxml.js | 4 + bits/75_xlml.js | 7 +- odsbits/60_content.js => bits/80_parseods.js | 12 +- odsbits/70_content.js => bits/81_writeods.js | 4 +- bits/83_ods.js | 61 +- bits/98_exports.js | 3 + bits/99_footer.js | 3 + demos/browserify/browserify.html | 2 + demos/webpack/Makefile | 2 +- demos/webpack/webpack.config.js | 3 +- demos/webpack/webpack.html | 2 + dist/ods.js | 745 ----------------- dist/ods.min.js | 2 - dist/ods.min.map | 1 - dist/xlsx.core.min.js | 22 +- dist/xlsx.core.min.map | 2 +- dist/xlsx.full.min.js | 24 +- dist/xlsx.full.min.map | 2 +- dist/xlsx.js | 622 ++++++++++++++- dist/xlsx.min.js | 21 +- dist/xlsx.min.map | 2 +- index.html | 4 +- misc/flowdeps.js | 3 + ods.flow.js | 748 ------------------ ods.js | 745 ----------------- odsbits/.npmignore | 1 - odsbits/00_header.js | 6 - odsbits/10_utils.js | 10 - odsbits/20_jsutils.js | 15 - odsbits/21_ziputils.js | 41 - odsbits/22_xmlutils.js | 100 --- odsbits/23_xlml.js | 9 - odsbits/35_rdf.js | 26 - odsbits/40_helpers.js | 20 - odsbits/80_parse.js | 13 - odsbits/85_write.js | 31 - odsbits/98_exports.js | 3 - odsbits/99_footer.js | 1 - package.json | 5 +- test.js | 50 +- tests.lst | 173 +++- xlsx.flow.js | 629 ++++++++++++++- xlsx.js | 622 ++++++++++++++- xlsxworker.flow.js | 2 - xlsxworker.js | 2 - xlsxworker1.flow.js | 2 - xlsxworker1.js | 2 - xlsxworker2.flow.js | 2 - xlsxworker2.js | 2 - 61 files changed, 2220 insertions(+), 2711 deletions(-) create mode 100644 CHANGELOG.md rename odsbits/30_manifest.js => bits/32_odmanrdf.js (57%) rename odsbits/50_formula.js => bits/65_fods.js (100%) rename odsbits/60_content.js => bits/80_parseods.js (98%) rename odsbits/70_content.js => bits/81_writeods.js (97%) delete mode 100644 dist/ods.js delete mode 100644 dist/ods.min.js delete mode 100644 dist/ods.min.map delete mode 100644 ods.flow.js delete mode 100644 ods.js delete mode 100644 odsbits/.npmignore delete mode 100644 odsbits/00_header.js delete mode 100644 odsbits/10_utils.js delete mode 100644 odsbits/20_jsutils.js delete mode 100644 odsbits/21_ziputils.js delete mode 100644 odsbits/22_xmlutils.js delete mode 100644 odsbits/23_xlml.js delete mode 100644 odsbits/35_rdf.js delete mode 100644 odsbits/40_helpers.js delete mode 100644 odsbits/80_parse.js delete mode 100644 odsbits/85_write.js delete mode 100644 odsbits/98_exports.js delete mode 100644 odsbits/99_footer.js diff --git a/.flowconfig b/.flowconfig index 21826f21..8462e3d8 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,6 +1,7 @@ [ignore] .*/node_modules/.* .*/dist/.* +.*/tmp/.* .*/test.js .*/bits/.* @@ -11,8 +12,6 @@ .*/demo/browser.js .*/shim.js -.*/odsbits/.* -.*/ods.js .*/xlsx.js .*/xlsxworker.js .*/xlsxworker1.js @@ -27,7 +26,6 @@ xlsxworker.flow.js xlsxworker1.flow.js xlsxworker2.flow.js xlsx.flow.js -ods.flow.js .*/bin/.*.njs .*/demo/browser.flow.js diff --git a/.gitignore b/.gitignore index e6b6c42b..77bb8fe4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ tmp *.htm *.html *.sheetjs +*.exe diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..ccbfb4f5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# CHANGELOG + +This log is intended to keep track of backwards-incompatible changes, including +but not limited to API changes and file location changes. Minor behavioral +changes may not be included if they are not expected to break existing code. + + +## 0.9.0 (2017-03-09) + +* Removed ods.js source. The xlsx.js source absorbed the ODS logic and exposes + the ODS variable, so projects should remove references to ods.js + diff --git a/Makefile b/Makefile index 71d61381..4e50086b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ LIB=xlsx FMT=xlsx xlsm xlsb ods xls xml misc full REQS=jszip.js ADDONS=dist/cpexcel.js -AUXTARGETS=ods.js +AUXTARGETS= CMDS=bin/xlsx.njs HTMLLINT=index.html @@ -62,23 +62,18 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution cat <(head -n 1 bits/00_header.js) $(REQS) $(ADDONS) $(TARGET) $(AUXTARGETS) > demos/requirejs/$(LIB).full.js .PHONY: dist-deps -dist-deps: ods.js ## Copy dependencies for distribution +dist-deps: ## Copy dependencies for distribution cp node_modules/codepage/dist/cpexcel.full.js dist/cpexcel.js cp jszip.js dist/jszip.js - cp ods.js dist/ods.js - uglifyjs $(UGLIFYOPTS) ods.js -o dist/ods.min.js --source-map dist/ods.min.map --preamble "$$(head -n 1 bits/00_header.js)" - misc/strip_sourcemap.sh dist/ods.min.js .PHONY: aux aux: $(AUXTARGETS) -.PHONY: ods -ods: ods.js - -ODSDEPS=$(sort $(wildcard odsbits/*.js)) -ods.flow.js: $(ODSDEPS) ## Build ODS support library - cat $^ | tr -d '\15\32' > $@ +.PHONY: nexe +nexe: xlsx.exe +xlsx.exe: bin/xlsx.js xlsx.js + nexe -i bin/xlsx.njs -o xlsx.exe ## Testing @@ -92,6 +87,9 @@ TESTFMT=$(patsubst %,test_%,$(FMT)) $(TESTFMT): test_%: FMTS=$* make test +.PHONY: demos +demos: demo-browserify demo-webpack demo-requirejs + .PHONY: demo-browserify demo-browserify: ## Run browserify demo build make -C demos/browserify @@ -102,6 +100,11 @@ demo-webpack: ## Run webpack demo build make -C demos/webpack @echo "start a local server and go to demos/webpack/webpack.html" +.PHONY: demo-requirejs +demo-requirejs: ## Run requirejs demo build + make -C demos/requirejs + @echo "start a local server and go to demos/requirejs/requirejs.html" + ## Code Checking .PHONY: lint diff --git a/README.md b/README.md index 8195c4bb..eb71e002 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,6 @@ be included directly: ```html - - ``` An appropriate version for each dependency is included in the dist/ directory. diff --git a/bits/00_header.js b/bits/00_header.js index ff45f1f8..8eefc1d8 100644 --- a/bits/00_header.js +++ b/bits/00_header.js @@ -2,5 +2,6 @@ /* vim: set ts=2: */ /*jshint -W041 */ /*jshint funcscope:true, eqnull:true */ +/*exported XLSX */ var XLSX = {}; (function make_xlsx(XLSX){ diff --git a/bits/01_version.js b/bits/01_version.js index d3e71bdf..636a1292 100644 --- a/bits/01_version.js +++ b/bits/01_version.js @@ -1 +1 @@ -XLSX.version = '0.8.8'; +XLSX.version = '0.9.0'; diff --git a/bits/20_jsutils.js b/bits/20_jsutils.js index f7348d38..d12c4383 100644 --- a/bits/20_jsutils.js +++ b/bits/20_jsutils.js @@ -35,6 +35,33 @@ function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ { return (epoch + 2209161600000) / (24 * 60 * 60 * 1000); } +/* ISO 8601 Duration */ +function parse_isodur(s) { + var sec = 0, mt = 0, time = false; + var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/); + if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration"); + for(var i = 1; i != m.length; ++i) { + if(!m[i]) continue; + mt = 1; + if(i > 3) time = true; + switch(m[i].substr(m[i].length-1)) { + case 'Y': + throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1)); + case 'D': mt *= 24; + /* falls through */ + case 'H': mt *= 60; + /* falls through */ + case 'M': + if(!time) throw new Error("Unsupported ISO Duration Field: M"); + else mt *= 60; + /* falls through */ + case 'S': break; + } + sec += mt * parseInt(m[i], 10); + } + return sec; +} + function cc2str(arr/*:Array*/)/*:string*/ { var o = ""; for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]); diff --git a/bits/21_ziputils.js b/bits/21_ziputils.js index 52b11a6f..b44752f9 100644 --- a/bits/21_ziputils.js +++ b/bits/21_ziputils.js @@ -22,6 +22,7 @@ function getdatabin(data) { function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); } /* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */ +/* OASIS does not comment on filename case sensitivity */ function safegetzipfile(zip, file/*:string*/) { var k = keys(zip.files); var f = file.toLowerCase(), g = f.replace(/\//g,'\\'); diff --git a/bits/22_xmlutils.js b/bits/22_xmlutils.js index 1d4d9cd4..6b4c23a1 100644 --- a/bits/22_xmlutils.js +++ b/bits/22_xmlutils.js @@ -1,4 +1,4 @@ -var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; +var attregexg=/([^\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g; var tagregex=/<[^>]*>/g; var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/; function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ { @@ -7,14 +7,21 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ { for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break; if(!skip_root) z[0] = tag.substr(0, eq); if(eq === tag.length) return z; - var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc=""; + var m = tag.match(attregexg), j=0, v="", i=0, q="", cc=""; if(m) for(i = 0; i != m.length; ++i) { cc = m[i]; for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break; q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1); for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break; - if(j===q.length) z[q] = v; - else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v; + if(j===q.length) { + //if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_")); // from ods + z[q] = v; + } + else { + var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1); + //if(z[k] && q.substr(j-3,3) == "ext") continue; // from ods + z[k] = v; + } } return z; } diff --git a/odsbits/30_manifest.js b/bits/32_odmanrdf.js similarity index 57% rename from odsbits/30_manifest.js rename to bits/32_odmanrdf.js index f4fbdac4..84a76470 100644 --- a/odsbits/30_manifest.js +++ b/bits/32_odmanrdf.js @@ -1,3 +1,4 @@ +/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */ /* Part 3 Section 4 Manifest File */ var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet"; function parse_manifest(d, opts) { @@ -27,3 +28,30 @@ function write_manifest(manifest/*:Array >*/, opts)/*:string*/ { o.push(''); return o.join(""); } + +/* Part 3 Section 6 Metadata Manifest File */ +function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) { + return [ + ' \n', + ' \n', + ' \n' + ].join(""); +} +function write_rdf_has(base/*:string*/, file/*:string*/) { + return [ + ' \n', + ' \n', + ' \n' + ].join(""); +} +function write_rdf(rdf, opts) { + var o = [XML_HEADER]; + o.push('\n'); + for(var i = 0; i != rdf.length; ++i) { + o.push(write_rdf_type(rdf[i][0], rdf[i][1])); + o.push(write_rdf_has("",rdf[i][0])); + } + o.push(write_rdf_type("","Document", "pkg")); + o.push(''); + return o.join(""); +} diff --git a/odsbits/50_formula.js b/bits/65_fods.js similarity index 100% rename from odsbits/50_formula.js rename to bits/65_fods.js diff --git a/bits/67_wsxml.js b/bits/67_wsxml.js index cdbfec2a..8f0fb8bc 100644 --- a/bits/67_wsxml.js +++ b/bits/67_wsxml.js @@ -249,6 +249,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess) { case 'n': p.v = parseFloat(p.v); break; case 's': sstr = strs[parseInt(p.v, 10)]; + if(typeof p.v == 'undefined') { + if(!opts.sheetStubs) continue; + p.t = "stub"; + } p.v = sstr.t; p.r = sstr.r; if(opts.cellHTML) p.h = sstr.h; diff --git a/bits/75_xlml.js b/bits/75_xlml.js index 5cdbee34..99e4747e 100644 --- a/bits/75_xlml.js +++ b/bits/75_xlml.js @@ -85,6 +85,7 @@ function process_style_xlml(styles, stag, opts) { function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o)/*:Workbook*/ { var nf = "General", sid = cell.StyleID, S = {}; o = o || {}; var interiors = []; + var i = 0; if(sid === undefined && row) sid = row.StyleID; if(sid === undefined && csty) sid = csty.StyleID; while(styles[sid] !== undefined) { @@ -150,13 +151,15 @@ function xlml_clean_comment(comment/*:any*/) { } function xlml_normalize(d)/*:string*/ { - if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8'); + if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); if(typeof d === 'string') return d; throw new Error("Bad input format: expected Buffer or string"); } /* TODO: Everything */ -var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg; +/* UOS uses CJK in tags */ +var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg; +//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg; function parse_xlml_xml(d, opts)/*:Workbook*/ { var str = debom(xlml_normalize(d)); if(str.substr(0,1000).indexOf("= 0) return parse_html(str, opts); diff --git a/odsbits/60_content.js b/bits/80_parseods.js similarity index 98% rename from odsbits/60_content.js rename to bits/80_parseods.js index 41824d5c..e408e4db 100644 --- a/odsbits/60_content.js +++ b/bits/80_parseods.js @@ -1,5 +1,9 @@ var parse_content_xml = (function() { + var parse_text_p = function(text, tag) { + return unescapexml(text.replace(//g," ").replace(/<[^>]*>/g,"")); + }; + var number_formats = { /* ods name: [short ssf fmt, long ssf fmt] */ day: ["d", "dd"], @@ -35,7 +39,7 @@ var parse_content_xml = (function() { case 'table': case '工作表': // 9.1.2 if(Rn[1]==='/') { - if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range); + if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range); if(merges.length) ws['!merges'] = merges; sheetag.name = utf8read(sheetag['名称'] || sheetag.name); SheetNames.push(sheetag.name); @@ -76,7 +80,7 @@ var parse_content_xml = (function() { mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0; mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0; mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; - q.F = get_utils().encode_range(mrange); + q.F = encode_range(mrange); arrayf.push([mrange, q.F]); } if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula); @@ -119,8 +123,8 @@ var parse_content_xml = (function() { if(textp) q.w = textp; if(!isstub || opts.cellStubs) { if(!(opts.sheetRows && opts.sheetRows < R)) { - ws[get_utils().encode_cell({r:R,c:C})] = q; - while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); + ws[encode_cell({r:R,c:C})] = q; + while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q); if(range.e.c <= C) range.e.c = C; } } else { C += rept; rept = 0; } diff --git a/odsbits/70_content.js b/bits/81_writeods.js similarity index 97% rename from odsbits/70_content.js rename to bits/81_writeods.js index 323f34f6..df30661c 100644 --- a/odsbits/70_content.js +++ b/bits/81_writeods.js @@ -4,13 +4,13 @@ var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() { /* Section 9 Tables */ var o = []; o.push(' \n'); - var R=0,C=0, range = get_utils().decode_range(ws['!ref']); + var R=0,C=0, range = decode_range(ws['!ref']); for(R = 0; R < range.s.r; ++R) o.push(' \n'); for(; R <= range.e.r; ++R) { o.push(' \n'); for(C=0; C < range.s.c; ++C) o.push(null_cell_xml); for(; C <= range.e.c; ++C) { - var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref]; + var ref = encode_cell({r:R, c:C}), cell = ws[ref]; if(cell) switch(cell.t) { case 'b': o.push(' ' + (cell.v ? 'TRUE' : 'FALSE') + '\n'); break; case 'n': o.push(' ' + (cell.w||cell.v) + '\n'); break; diff --git a/bits/83_ods.js b/bits/83_ods.js index 0333b9b6..e0e07025 100644 --- a/bits/83_ods.js +++ b/bits/83_ods.js @@ -1,21 +1,44 @@ -/* Helper functions to call out to ODS */ +/* Part 3: Packages */ +function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) { + opts = opts || ({}/*:any*/); + var ods = !!safegetzipfile(zip, 'objectdata'); + if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts); + var content = getzipdata(zip, 'content.xml'); + if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file"); + return parse_content_xml(ods ? content : utf8read(content), opts); +} +function parse_fods(data/*:string*/, opts/*:?ParseOpts*/) { + return parse_content_xml(data, opts); +} -function get_ods() { - if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./ods.js'); - return ODS; -} -function parse_ods(zip, opts) { - get_ods(); - if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS"); - return ODS.parse_ods(zip, opts); -} -function write_ods(wb, opts) { - get_ods(); - if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS"); - return ODS.write_ods(wb, opts); -} -function parse_fods(data, opts) { - get_ods(); - if(typeof ODS === 'undefined' || !ODS.parse_fods) throw new Error("Unsupported ODS"); - return ODS.parse_fods(data, opts); +function write_ods(wb/*:any*/, opts/*:any*/) { + if(opts.bookType == "fods") return write_content_xml(wb, opts); + + /*:: if(!jszip) throw new Error("JSZip is not available"); */ + var zip = new jszip(); + var f = ""; + + var manifest/*:Array >*/ = []; + var rdf = []; + + /* 3:3.3 and 2:2.2.4 */ + f = "mimetype"; + zip.file(f, "application/vnd.oasis.opendocument.spreadsheet"); + + /* Part 1 Section 2.2 Documents */ + f = "content.xml"; + zip.file(f, write_content_xml(wb, opts)); + manifest.push([f, "text/xml"]); + rdf.push([f, "ContentFile"]); + + /* Part 3 Section 6 Metadata Manifest File */ + f = "manifest.rdf"; + zip.file(f, write_rdf(rdf, opts)); + manifest.push([f, "application/rdf+xml"]); + + /* Part 3 Section 4 Manifest File */ + f = "META-INF/manifest.xml"; + zip.file(f, write_manifest(manifest, opts)); + + return zip; } diff --git a/bits/98_exports.js b/bits/98_exports.js index df1acd66..8e9fd8a0 100644 --- a/bits/98_exports.js +++ b/bits/98_exports.js @@ -1,4 +1,7 @@ XLSX.parse_xlscfb = parse_xlscfb; +XLSX.parse_ods = parse_ods; +XLSX.parse_fods = parse_fods; +XLSX.write_ods = write_ods; XLSX.parse_zip = parse_zip; XLSX.read = readSync; //xlsread XLSX.readFile = readFileSync; //readFile diff --git a/bits/99_footer.js b/bits/99_footer.js index 50e5f5e9..0670c549 100644 --- a/bits/99_footer.js +++ b/bits/99_footer.js @@ -1,2 +1,5 @@ })(typeof exports !== 'undefined' ? exports : XLSX); +/*exported XLS */ var XLS = XLSX; +/*exported ODS */ +var ODS = XLSX; diff --git a/demos/browserify/browserify.html b/demos/browserify/browserify.html index 2b40711a..2c72df89 100644 --- a/demos/browserify/browserify.html +++ b/demos/browserify/browserify.html @@ -41,6 +41,8 @@ Use readAsBinaryString: (when available) - -