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 21826f2..8462e3d 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 e6b6c42..77bb8fe 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 0000000..ccbfb4f --- /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 71d6138..4e50086 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 8195c4b..eb71e00 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 ff45f1f..8eefc1d 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 d3e71bd..636a129 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 f7348d3..d12c438 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 52b11a6..b44752f 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 1d4d9cd..6b4c23a 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 f4fbdac..84a7647 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 cdbfec2..8f0fb8b 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 5cdbee3..99e4747 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 41824d5..e408e4d 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 323f34f..df30661 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 0333b9b..e0e0702 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 df1acd6..8e9fd8a 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 50e5f5e..0670c54 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 2b40711..2c72df8 100644 --- a/demos/browserify/browserify.html +++ b/demos/browserify/browserify.html @@ -41,6 +41,8 @@ Use readAsBinaryString: (when available) - -