forked from sheetjs/sheetjs
		
	experimental dense representation
- browser demo save file in global (fixes #573 h/t @WildDusk) - flesh out XLSB record expectations (fixes #624 h/t @pgeeh) - `dense` mode (fixes #34 h/t @schleumer)
This commit is contained in:
		
							parent
							
								
									d086dbecbf
								
							
						
					
					
						commit
						f43cacaf5e
					
				| @ -40,6 +40,7 @@ program | ||||
| 	.option('--perf', 'do not generate output') | ||||
| 	.option('--all', 'parse everything; write as much as possible') | ||||
| 	.option('--dev', 'development mode') | ||||
| 	.option('--sparse', 'sparse mode') | ||||
| 	.option('--read', 'read but do not print out contents') | ||||
| 	.option('-q, --quiet', 'quiet mode'); | ||||
| 
 | ||||
| @ -111,6 +112,7 @@ if(program.all) { | ||||
| 	opts.sheetStubs = true; | ||||
| 	opts.cellDates = true; | ||||
| } | ||||
| if(program.sparse) opts.dense = false; else opts.dense = true; | ||||
| 
 | ||||
| if(program.dev) { | ||||
| 	X.verbose = 2; | ||||
|  | ||||
							
								
								
									
										1
									
								
								bits/03_dense.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								bits/03_dense.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| var DENSE = false; | ||||
| @ -6,7 +6,8 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ { | ||||
| 
 | ||||
| function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 	var o = opts || {}; | ||||
| 	var ws/*:Worksheet*/ = ({}/*:any*/); | ||||
| 	if(DENSE != null) o.dense = DENSE; | ||||
| 	var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 	var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/); | ||||
| 	for(var R = 0; R != data.length; ++R) { | ||||
| 		for(var C = 0; C != data[R].length; ++C) { | ||||
| @ -16,7 +17,6 @@ function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			if(range.s.c > C) range.s.c = C; | ||||
| 			if(range.e.r < R) range.e.r = R; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| 			var cell_ref = encode_cell(({c:C,r:R}/*:any*/)); | ||||
| 			if(cell.v === null) { if(!o.cellStubs) continue; cell.t = 'z'; } | ||||
| 			else if(typeof cell.v === 'number') cell.t = 'n'; | ||||
| 			else if(typeof cell.v === 'boolean') cell.t = 'b'; | ||||
| @ -26,7 +26,13 @@ function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); } | ||||
| 			} | ||||
| 			else cell.t = 's'; | ||||
| 			ws[cell_ref] = cell; | ||||
| 			if(o.dense) { | ||||
| 				if(!ws[R]) ws[R] = []; | ||||
| 				ws[R][C] = cell; | ||||
| 			} else { | ||||
| 				var cell_ref = encode_cell(({c:C,r:R}/*:any*/)); | ||||
| 				ws[cell_ref] = cell; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(range.s.c < 10000000) ws['!ref'] = encode_range(range); | ||||
|  | ||||
| @ -122,7 +122,7 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.ms-excel.Survey+xml": "TODO", | ||||
| 
 | ||||
| 	/* Drawing */ | ||||
| 	"application/vnd.openxmlformats-officedocument.drawing+xml": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.drawing+xml": "drawings", | ||||
| 	"application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO", | ||||
| @ -193,7 +193,7 @@ function parse_ct(data/*:?string*/, opts) { | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		TODO:[], xmlns: "" }/*:any*/); | ||||
| 	if(!data || !data.match) return ct; | ||||
| 	var ctext = {}; | ||||
| @ -256,7 +256,7 @@ function write_ct(ct, opts)/*:string*/ { | ||||
| 		} | ||||
| 	}; | ||||
| 	var f2 = function(w) { | ||||
| 		ct[w].forEach(function(v) { | ||||
| 		(ct[w]||[]).forEach(function(v) { | ||||
| 			o[o.length] = (writextag('Override', null, { | ||||
| 				'PartName': (v[0] == '/' ? "":"/") + v, | ||||
| 				'ContentType': CT_LIST[w][opts.bookType || 'xlsx'] | ||||
| @ -273,11 +273,13 @@ function write_ct(ct, opts)/*:string*/ { | ||||
| 	}; | ||||
| 	f1('workbooks'); | ||||
| 	f2('sheets'); | ||||
| 	f2('charts'); | ||||
| 	f3('themes'); | ||||
| 	['strs', 'styles'].forEach(f1); | ||||
| 	['coreprops', 'extprops', 'custprops'].forEach(f3); | ||||
| 	f3('vba'); | ||||
| 	f2('comments'); | ||||
| 	f3('comments'); | ||||
| 	f3('drawings'); | ||||
| 	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
|  | ||||
| @ -44,11 +44,9 @@ var RELS_ROOT = writextag('Relationships', null, { | ||||
| 
 | ||||
| /* TODO */ | ||||
| function write_rels(rels)/*:string*/ { | ||||
| 	var o = []; | ||||
| 	o[o.length] = (XML_HEADER); | ||||
| 	o[o.length] = (RELS_ROOT); | ||||
| 	keys(rels['!id']).forEach(function(rid) { var rel = rels['!id'][rid]; | ||||
| 		o[o.length] = (writextag('Relationship', null, rel)); | ||||
| 	var o = [XML_HEADER, RELS_ROOT]; | ||||
| 	keys(rels['!id']).forEach(function(rid) { | ||||
| 		o[o.length] = (writextag('Relationship', null, rels['!id'][rid])); | ||||
| 	}); | ||||
| 	if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
|  | ||||
| @ -261,10 +261,12 @@ var SYLK = (function() { | ||||
| 		var preamble/*:Array<string>*/ = ["ID;PWXL;N;E"], o/*:Array<string>*/ = []; | ||||
| 		preamble.push("P;PGeneral"); | ||||
| 		var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 		var dense = Array.isArray(ws); | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 				var coord = encode_cell({r:R,c:C}); | ||||
| 				if(!(cell = ws[coord]) || cell.v == null) continue; | ||||
| 				cell = dense ? (ws[R]||[])[C]: ws[coord]; | ||||
| 				if(!cell || cell.v == null) continue; | ||||
| 				o.push(write_ws_cell_sylk(cell, ws, R, C, opts)); | ||||
| 			} | ||||
| 		} | ||||
| @ -337,6 +339,7 @@ var DIF = (function() { | ||||
| 		return function sheet_to_dif(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 			var o/*:Array<string>*/ = []; | ||||
| 			var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 			var dense = Array.isArray(ws); | ||||
| 			push_field(o, "TABLE", 0, 1, "sheetjs"); | ||||
| 			push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,""); | ||||
| 			push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,""); | ||||
| @ -345,7 +348,8 @@ var DIF = (function() { | ||||
| 				push_value(o, -1, 0, "BOT"); | ||||
| 				for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 					var coord = encode_cell({r:R,c:C}); | ||||
| 					if(!(cell = ws[coord]) || cell.v == null) { push_value(o, 1, 0, ""); continue;} | ||||
| 					cell = dense ? (ws[R]||[])[C] : ws[coord]; | ||||
| 					if(!cell || cell.v == null) { push_value(o, 1, 0, ""); continue;} | ||||
| 					switch(cell.t) { | ||||
| 						case 'n': push_value(o, 0, (/*cell.w ||*/ cell.v), "V"); break; | ||||
| 						case 'b': push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE"); break; | ||||
| @ -402,8 +406,10 @@ var PRN = (function() { | ||||
| 	} | ||||
| 
 | ||||
| 	function dsv_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ { | ||||
| 		var o = opts || {}; | ||||
| 		var sep = ""; | ||||
| 		var ws/*:Worksheet*/ = ({}/*:any*/); | ||||
| 		if(DENSE != null) o.dense = DENSE; | ||||
| 		var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/); | ||||
| 
 | ||||
| 		/* known sep */ | ||||
| @ -423,7 +429,8 @@ var PRN = (function() { | ||||
| 			else if(s == "FALSE") { cell.t = 'b'; cell.v = false; } | ||||
| 			else if(!isNaN(v = parseFloat(s))) { cell.t = 'n'; cell.w = s; cell.v = v; } | ||||
| 			else { cell.t = 's'; cell.v = s.replace(/^"/,"").replace(/"$/,"").replace(/""/g,'"'); } | ||||
| 			ws[encode_cell({c:C,r:R})] = cell; | ||||
| 			if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			else ws[encode_cell({c:C,r:R})] = cell; | ||||
| 			start = end+1; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| 			if(range.e.r < R) range.e.r = R; | ||||
| @ -456,11 +463,13 @@ var PRN = (function() { | ||||
| 	function sheet_to_prn(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 		var o/*:Array<string>*/ = []; | ||||
| 		var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 		var dense = Array.isArray(ws); | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			var oo = []; | ||||
| 			for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 				var coord = encode_cell({r:R,c:C}); | ||||
| 				if(!(cell = ws[coord]) || cell.v == null) { oo.push("          "); continue; } | ||||
| 				cell = dense ? (ws[R]||[])[C] : ws[coord]; | ||||
| 				if(!cell || cell.v == null) { oo.push("          "); continue; } | ||||
| 				var w = (cell.w || (format_cell(cell), cell.w) || "").substr(0,10); | ||||
| 				while(w.length < 10) w += " "; | ||||
| 				oo.push(w + (C == 0 ? " " : "")); | ||||
|  | ||||
| @ -27,8 +27,8 @@ var WK_ = (function() { | ||||
| 	function lotus_to_workbook_buf(d,opts)/*:Workbook*/ { | ||||
| 		if(!d) return d; | ||||
| 		var o = opts || {}; | ||||
| 
 | ||||
| 		var s = {}, n = "Sheet1", sidx = 0; | ||||
| 		if(DENSE != null) o.dense = DENSE; | ||||
| 		var s = (o.dense ? [] : {}), n = "Sheet1", sidx = 0; | ||||
| 		var sheets = {}, snames = [n]; | ||||
| 
 | ||||
| 		var refguess = {s: {r:0, c:0}, e: {r:0, c:0} }; | ||||
| @ -45,13 +45,16 @@ var WK_ = (function() { | ||||
| 					break; | ||||
| 				case 0x06: refguess = val; break; /* RANGE */ | ||||
| 				case 0x0F: /* LABEL */ | ||||
| 					if(!opts.qpro) val[1].v = val[1].v.substr(1); | ||||
| 					if(!o.qpro) val[1].v = val[1].v.substr(1); | ||||
| 					/* falls through */ | ||||
| 				case 0x0D: /* INTEGER */ | ||||
| 				case 0x0E: /* NUMBER */ | ||||
| 				case 0x10: /* FORMULA */ | ||||
| 				case 0x33: /* STRING */ | ||||
| 					s[encode_cell(val[0])] = val[1]; | ||||
| 					if(o.dense) { | ||||
| 						if(!s[val[0].r]) s[val[0].r] = []; | ||||
| 						s[val[0].r][val[0].c] = val[1]; | ||||
| 					} else s[encode_cell(val[0])] = val[1]; | ||||
| 					/* TODO: FORMAT */ | ||||
| 					break; | ||||
| 			} else switch(RT) { | ||||
| @ -67,7 +70,7 @@ var WK_ = (function() { | ||||
| 					if(val[3] > sidx) { | ||||
| 						s["!ref"] = encode_range(refguess); | ||||
| 						sheets[n] = s; | ||||
| 						s = {}; | ||||
| 						s = (o.dense ? [] : {}); | ||||
| 						refguess = {s: {r:0, c:0}, e: {r:0, c:0} }; | ||||
| 						sidx = val[3]; n = "Sheet" + (sidx + 1); | ||||
| 						snames.push(n); | ||||
|  | ||||
| @ -12,7 +12,6 @@ function parse_sst_bin(data, opts)/*:SST*/ { | ||||
| 			case 'BrtBeginSst': s.Count = val[0]; s.Unique = val[1]; break; | ||||
| 			case 'BrtSSTItem': s.push(val); break; | ||||
| 			case 'BrtEndSst': return true; | ||||
| 			/* TODO: produce a test case with a future record */ | ||||
| 			case 'BrtFRTBegin': pass = true; break; | ||||
| 			case 'BrtFRTEnd': pass = false; break; | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R.n); | ||||
| @ -34,6 +33,7 @@ function write_sst_bin(sst, opts) { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst)); | ||||
| 	for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i])); | ||||
| 	/* FRTSST */ | ||||
| 	write_record(ba, "BrtEndSst"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -47,7 +47,7 @@ function parse_sty_bin(data, themes, opts) { | ||||
| 	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; | ||||
| 
 | ||||
| 	styles.CellXf = []; | ||||
| 	var state = ""; /* TODO: this should be a stack */ | ||||
| 	var state = []; | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function hopper_sty(val, R, RT) { | ||||
| 		switch(R.n) { | ||||
| @ -59,7 +59,7 @@ function parse_sty_bin(data, themes, opts) { | ||||
| 			case 'BrtFill': break; /* TODO */ | ||||
| 			case 'BrtBorder': break; /* TODO */ | ||||
| 			case 'BrtXF': | ||||
| 				if(state === "CELLXFS") { | ||||
| 				if(state[state.length - 1] == "BrtBeginCellXFs") { | ||||
| 					styles.CellXf.push(val); | ||||
| 				} | ||||
| 				break; /* TODO */ | ||||
| @ -67,48 +67,23 @@ function parse_sty_bin(data, themes, opts) { | ||||
| 			case 'BrtDXF': break; /* TODO */ | ||||
| 			case 'BrtMRUColor': break; /* TODO */ | ||||
| 			case 'BrtIndexedColor': break; /* TODO */ | ||||
| 			case 'BrtBeginStyleSheet': break; | ||||
| 			case 'BrtEndStyleSheet': break; | ||||
| 			case 'BrtBeginTableStyle': break; | ||||
| 
 | ||||
| 			case 'BrtDXF14': break; | ||||
| 			case 'BrtDXF15': break; | ||||
| 			case 'BrtUid': break; | ||||
| 			case 'BrtSlicerStyleElement': break; | ||||
| 			case 'BrtTableStyleElement': break; | ||||
| 			case 'BrtEndTableStyle': break; | ||||
| 			case 'BrtBeginFmts': state = "FMTS"; break; | ||||
| 			case 'BrtEndFmts': state = ""; break; | ||||
| 			case 'BrtBeginFonts': state = "FONTS"; break; | ||||
| 			case 'BrtEndFonts': state = ""; break; | ||||
| 			case 'BrtACBegin': state = "ACFONTS"; break; | ||||
| 			case 'BrtACEnd': state = ""; break; | ||||
| 			case 'BrtBeginFills': state = "FILLS"; break; | ||||
| 			case 'BrtEndFills': state = ""; break; | ||||
| 			case 'BrtBeginBorders': state = "BORDERS"; break; | ||||
| 			case 'BrtEndBorders': state = ""; break; | ||||
| 			case 'BrtBeginCellStyleXFs': state = "CELLSTYLEXFS"; break; | ||||
| 			case 'BrtEndCellStyleXFs': state = ""; break; | ||||
| 			case 'BrtBeginCellXFs': state = "CELLXFS"; break; | ||||
| 			case 'BrtEndCellXFs': state = ""; break; | ||||
| 			case 'BrtBeginStyles': state = "STYLES"; break; | ||||
| 			case 'BrtEndStyles': state = ""; break; | ||||
| 			case 'BrtBeginDXFs': state = "DXFS"; break; | ||||
| 			case 'BrtEndDXFs': state = ""; break; | ||||
| 			case 'BrtBeginTableStyles': state = "TABLESTYLES"; break; | ||||
| 			case 'BrtEndTableStyles': state = ""; break; | ||||
| 			case 'BrtBeginColorPalette': state = "COLORPALETTE"; break; | ||||
| 			case 'BrtEndColorPalette': state = ""; break; | ||||
| 			case 'BrtBeginIndexedColors': state = "INDEXEDCOLORS"; break; | ||||
| 			case 'BrtEndIndexedColors': state = ""; break; | ||||
| 			case 'BrtBeginMRUColors': state = "MRUCOLORS"; break; | ||||
| 			case 'BrtEndMRUColors': state = ""; break; | ||||
| 			case 'BrtTimelineStyleElement': break; | ||||
| 
 | ||||
| 			case 'BrtFRTBegin': pass = true; break; | ||||
| 			case 'BrtFRTEnd': pass = false; break; | ||||
| 			case 'BrtBeginStyleSheetExt14': break; | ||||
| 			case 'BrtBeginSlicerStyles': break; | ||||
| 			case 'BrtEndSlicerStyles': break; | ||||
| 			case 'BrtBeginTimelineStylesheetExt15': break; | ||||
| 			case 'BrtEndTimelineStylesheetExt15': break; | ||||
| 			case 'BrtBeginTimelineStyles': break; | ||||
| 			case 'BrtEndTimelineStyles': break; | ||||
| 			case 'BrtEndStyleSheetExt14': break; | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R.n); | ||||
| 			case 'BrtACBegin': state.push(R.n); break; | ||||
| 			case 'BrtACEnd': state.pop(); break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if((R.n||"").indexOf("Begin") > 0) state.push(R.n); | ||||
| 				else if((R.n||"").indexOf("End") > 0) state.pop(); | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R.n); | ||||
| 		} | ||||
| 	}); | ||||
| 	return styles; | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; | ||||
| RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"; | ||||
| /* 20.5 DrawingML - SpreadsheetML Drawing */ | ||||
| function parse_drawing(data, rels/*:any*/) { | ||||
| 	if(!data) return "??"; | ||||
| @ -16,3 +18,4 @@ function parse_drawing(data, rels/*:any*/) { | ||||
| 
 | ||||
| 	return rels['!id'][id].Target; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,11 +19,18 @@ function parse_comments(zip, dirComments, sheets, sheetRels, opts) { | ||||
| } | ||||
| 
 | ||||
| function insertCommentsIntoSheet(sheetName, sheet, comments) { | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	var cell, r; | ||||
| 	comments.forEach(function(comment) { | ||||
| 		var cell = sheet[comment.ref]; | ||||
| 		if(dense) { | ||||
| 			r = decode_cell(comment.ref); | ||||
| 			if(!sheet[r.r]) sheet[r.r] = []; | ||||
| 			cell = sheet[r.r][r.c]; | ||||
| 		} else cell = sheet[comment.ref]; | ||||
| 		if (!cell) { | ||||
| 			cell = {}; | ||||
| 			sheet[comment.ref] = cell; | ||||
| 			if(dense) sheet[r.r][r.c] = cell; | ||||
| 			else sheet[comment.ref] = cell; | ||||
| 			var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1"); | ||||
| 			var thisCell = decode_cell(comment.ref); | ||||
| 			if(range.s.r > thisCell.r) range.s.r = thisCell.r; | ||||
|  | ||||
| @ -42,13 +42,17 @@ function parse_comments_bin(data, opts) { | ||||
| 				if(opts.sheetRows && opts.sheetRows <= c.rfx.r) break; | ||||
| 				if(!c.t) c.t = ""; | ||||
| 				delete c.rfx; out.push(c); break; | ||||
| 			case 'BrtBeginComments': break; | ||||
| 			case 'BrtEndComments': break; | ||||
| 			case 'BrtBeginCommentAuthors': break; | ||||
| 			case 'BrtEndCommentAuthors': break; | ||||
| 			case 'BrtBeginCommentList': break; | ||||
| 			case 'BrtEndCommentList': break; | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R.n); | ||||
| 
 | ||||
| 			case 'BrtUid': break; | ||||
| 			case 'BrtFRTBegin': pass = true; break; | ||||
| 			case 'BrtFRTEnd': pass = false; break; | ||||
| 			case 'BrtACBegin': break; | ||||
| 			case 'BrtACEnd': break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if((R.n||"").indexOf("Begin") > 0){} | ||||
| 				else if((R.n||"").indexOf("End") > 0){} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R.n); | ||||
| 		} | ||||
| 	}); | ||||
| 	return out; | ||||
|  | ||||
| @ -10,8 +10,9 @@ var colregex = /<(?:\w*:)?col[^>]*[\/]?>/g; | ||||
| /* 18.3 Worksheets */ | ||||
| function parse_ws_xml(data/*:?string*/, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| 	if(DENSE != null) opts.dense = DENSE; | ||||
| 	/* 18.3.1.99 worksheet CT_Worksheet */ | ||||
| 	var s = ({}/*:any*/); | ||||
| 	var s = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 
 | ||||
| 	/* 18.3.1.35 dimension CT_SheetDimension ? */ | ||||
| 	// $FlowIgnore
 | ||||
| @ -89,6 +90,7 @@ function write_ws_xml_protection(sp)/*:string*/ { | ||||
| } | ||||
| 
 | ||||
| function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) { | ||||
| 	var dense = Array.isArray(s); | ||||
| 	for(var i = 0; i != data.length; ++i) { | ||||
| 		var val = parsexmltag(data[i], true); | ||||
| 		if(!val.ref) return; | ||||
| @ -106,8 +108,14 @@ function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) { | ||||
| 		var rng = safe_decode_range(val.ref); | ||||
| 		for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) { | ||||
| 			var addr = encode_cell({c:C,r:R}); | ||||
| 			if(!s[addr]) s[addr] = {t:"z",v:undefined}; | ||||
| 			s[addr].l = val; | ||||
| 			if(dense) { | ||||
| 				if(!s[R]) s[R] = []; | ||||
| 				if(!s[R][C]) s[R][C] = {t:"z",v:undefined}; | ||||
| 				s[R][C].l = val; | ||||
| 			} else { | ||||
| 				if(!s[addr]) s[addr] = {t:"z",v:undefined}; | ||||
| 				s[addr].l = val; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -191,6 +199,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { | ||||
| 	var fmtid = 0, fillid = 0, do_format = Array.isArray(styles.CellXf), cf; | ||||
| 	var arrayf = []; | ||||
| 	var sharedf = []; | ||||
| 	var dense = Array.isArray(s); | ||||
| 	for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) { | ||||
| 		x = marr[mt].trim(); | ||||
| 		var xlen = x.length; | ||||
| @ -305,21 +314,27 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { | ||||
| 			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { | ||||
| 				var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); } | ||||
| 			} | ||||
| 			s[tag.r] = p; | ||||
| 			if(dense) { | ||||
| 				var _r = decode_cell(tag.r); | ||||
| 				if(!s[_r.r]) s[_r.r] = []; | ||||
| 				s[_r.r][_r.c] = p; | ||||
| 			} else s[tag.r] = p; | ||||
| 		} | ||||
| 	} | ||||
| }; })(); | ||||
| 
 | ||||
| function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 	var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows']; | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		r = []; | ||||
| 		rr = encode_row(R); | ||||
| 		for(C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			ref = cols[C] + rr; | ||||
| 			if(ws[ref] === undefined) continue; | ||||
| 			if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell); | ||||
| 			var _cell = dense ? (ws[R]||[])[C]: ws[ref]; | ||||
| 			if(_cell === undefined) continue; | ||||
| 			if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell); | ||||
| 		} | ||||
| 		if(r.length > 0) { | ||||
| 			var params = ({r:rr}/*:any*/); | ||||
| @ -350,6 +365,7 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 	var ref = ws['!ref']; if(ref === undefined) ref = 'A1'; | ||||
| 	if(!rels) rels = {}; | ||||
| 	ws['!comments'] = []; | ||||
| 	ws['!drawing'] = []; | ||||
| 
 | ||||
| 	o[o.length] = (writextag('sheetPr', null, {'codeName': escapexml(wb.SheetNames[idx])})); | ||||
| 	o[o.length] = (writextag('dimension', null, {'ref': ref})); | ||||
| @ -385,12 +401,20 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 	} | ||||
| 	delete ws['!links']; | ||||
| 
 | ||||
| 	var hfidx = o.length; | ||||
| 	o[o.length] = ""; | ||||
| 
 | ||||
| 	if(ws['!drawing'].length > 0) { | ||||
| 		rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW); | ||||
| 		ws['!drawing'].rid = rId; | ||||
| 		o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId}); | ||||
| 	} | ||||
| 	else delete ws['!drawing']; | ||||
| 	if(ws['!comments'].length > 0) { | ||||
| 		rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML); | ||||
| 		o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId}); | ||||
| 		ws['!legacy'] = rId; | ||||
| 	} | ||||
| // <legacyDrawing r:id="rId1"/>
 | ||||
| 
 | ||||
| 	if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
|  | ||||
							
								
								
									
										235
									
								
								bits/68_wsbin.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										235
									
								
								bits/68_wsbin.js
									
									
									
									
									
								
							| @ -26,7 +26,8 @@ function write_BrtRowHdr(R/*:number*/, range, ws) { | ||||
| 		var first = -1, last = -1; | ||||
| 		for(var j = (i<<10); j < ((i+1)<<10); ++j) { | ||||
| 			caddr.c = j; | ||||
| 			if(ws[encode_cell(caddr)]) { if(first < 0) first = j; last = j; } | ||||
| 			var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)]; | ||||
| 			if(cell) { if(first < 0) first = j; last = j; } | ||||
| 		} | ||||
| 		if(first < 0) continue; | ||||
| 		++ncolspan; | ||||
| @ -289,18 +290,19 @@ function write_BrtColInfo(C/*:number*/, col, o) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.61 Worksheet */ | ||||
| function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| 	var opts = _opts || {}; | ||||
| 	if(!rels) rels = {'!id':{}}; | ||||
| 	var s = {}; | ||||
| 	if(DENSE != null) opts.dense = DENSE; | ||||
| 	var s = opts.dense ? [] : {}; | ||||
| 
 | ||||
| 	var ref; | ||||
| 	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} }; | ||||
| 
 | ||||
| 	var pass = false, end = false; | ||||
| 	var row, p, cf, R, C, addr, sstr, rr; | ||||
| 	var row, p, cf, R, C, addr, sstr, rr, cell; | ||||
| 	var mergecells = []; | ||||
| 	if(!opts) opts = {}; | ||||
| 	opts.biff = 12; | ||||
| 	opts['!row'] = 0; | ||||
| 
 | ||||
| @ -319,14 +321,14 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 	var defwidth = 0, defheight = 0; // twips / MDW respectively
 | ||||
| 	var seencol = false; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, Record) { | ||||
| 	recordhopper(data, function ws_parse(val, Record, RT) { | ||||
| 		if(end) return; | ||||
| 		switch(Record.n) { | ||||
| 			case 'BrtWsDim': ref = val; break; | ||||
| 			case 'BrtRowHdr': | ||||
| 				row = val; | ||||
| 				if(opts.sheetRows && opts.sheetRows <= row.r) end=true; | ||||
| 				rr = encode_row(row.r); | ||||
| 				rr = encode_row(R = row.r); | ||||
| 				opts['!row'] = row.r; | ||||
| 				break; | ||||
| 
 | ||||
| @ -349,7 +351,9 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 					case 'str': p.t = 's'; p.v = utf8read(val[1]); break; | ||||
| 				} | ||||
| 				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts, themes, styles); | ||||
| 				s[encode_col(C=val[0].c) + rr] = p; | ||||
| 				C = val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| 				if(opts.cellFormula) { | ||||
| 					af = false; | ||||
| 					for(ai = 0; ai < array_formulae.length; ++ai) { | ||||
| @ -370,18 +374,18 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtCellBlank': if(!opts.sheetStubs) break; | ||||
| 			case 'BrtCellBlank': | ||||
| 				if(!opts.sheetStubs) break; | ||||
| 				p = ({t:'z',v:undefined}/*:any*/); | ||||
| 				s[encode_col(C=val[0].c) + rr] = p; | ||||
| 				C = val[0].c; | ||||
| 				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; } | ||||
| 				else s[encode_col(C) + rr] = p; | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| 				if(refguess.e.c < C) refguess.e.c = C; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* Merge Cells */ | ||||
| 			case 'BrtBeginMergeCells': break; | ||||
| 			case 'BrtEndMergeCells': break; | ||||
| 			case 'BrtMergeCell': mergecells.push(val); break; | ||||
| 
 | ||||
| 			case 'BrtHLink': | ||||
| @ -392,140 +396,109 @@ function parse_ws_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 					val.Rel = rel; | ||||
| 				} | ||||
| 				for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) { | ||||
| 					addr = encode_cell({c:C,r:R}); | ||||
| 					if(!s[addr]) s[addr] = {t:'s',v:undefined}; | ||||
| 					s[addr].l = val; | ||||
| 					if(opts.dense) { | ||||
| 						if(!s[R]) s[R] = []; | ||||
| 						if(!s[R][C]) s[R][C] = {t:'z',v:undefined}; | ||||
| 						s[R][C].l = val; | ||||
| 					} else { | ||||
| 						addr = encode_cell({c:C,r:R}); | ||||
| 						if(!s[addr]) s[addr] = {t:'z',v:undefined}; | ||||
| 						s[addr].l = val; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtArrFmla': if(!opts.cellFormula) break; | ||||
| 			case 'BrtArrFmla': | ||||
| 				if(!opts.cellFormula) break; | ||||
| 				array_formulae.push(val); | ||||
| 				s[encode_col(C) + rr].f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				s[encode_col(C) + rr].F = encode_range(val[0]); | ||||
| 				cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]); | ||||
| 				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				cell.F = encode_range(val[0]); | ||||
| 				break; | ||||
| 			case 'BrtShrFmla': if(!opts.cellFormula) break; | ||||
| 				// TODO
 | ||||
| 			case 'BrtShrFmla': | ||||
| 				if(!opts.cellFormula) break; | ||||
| 				shared_formulae[encode_cell(val[0].s)] = val[1]; | ||||
| 				s[encode_col(C) + rr].f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]); | ||||
| 				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				break; | ||||
| 
 | ||||
| 			/* identical to 'ColInfo' in XLS */ | ||||
| 			case 'BrtColInfo': { | ||||
| 			case 'BrtColInfo': | ||||
| 				if(!opts.cellStyles) break; | ||||
| 				while(val.e >= val.s) { | ||||
| 					colinfo[val.e--] = { width: val.w/256 }; | ||||
| 					if(!seencol) { seencol = true; find_mdw_colw(val.w/256); } | ||||
| 					process_col(colinfo[val.e+1]); | ||||
| 				} | ||||
| 			} break; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtAFilterDateGroupItem': break; | ||||
| 			case 'BrtActiveX': break; | ||||
| 			case 'BrtBigName': break; | ||||
| 			case 'BrtBkHim': break; | ||||
| 			case 'BrtBrk': break; | ||||
| 			case 'BrtCFIcon': break; | ||||
| 			case 'BrtCFRuleExt': break; | ||||
| 			case 'BrtCFVO': break; | ||||
| 			case 'BrtCFVO14': break; | ||||
| 			case 'BrtCellIgnoreEC': break; | ||||
| 			case 'BrtCellIgnoreEC14': break; | ||||
| 			case 'BrtCellMeta': break; | ||||
| 			case 'BrtCellSmartTagProperty': break; | ||||
| 			case 'BrtCellWatch': break; | ||||
| 			case 'BrtColor': break; | ||||
| 			case 'BrtColor14': break; | ||||
| 			case 'BrtColorFilter': break; | ||||
| 			case 'BrtCustomFilter': break; | ||||
| 			case 'BrtCustomFilter14': break; | ||||
| 			case 'BrtDRef': break; | ||||
| 			case 'BrtDVal': break; | ||||
| 			case 'BrtDVal14': break; | ||||
| 			case 'BrtDValList': break; | ||||
| 			case 'BrtDrawing': break; | ||||
| 			case 'BrtDynamicFilter': break; | ||||
| 			case 'BrtFilter': break; | ||||
| 			case 'BrtFilter14': break; | ||||
| 			case 'BrtIconFilter': break; | ||||
| 			case 'BrtIconFilter14': break; | ||||
| 			case 'BrtLegacyDrawing': break; | ||||
| 			case 'BrtLegacyDrawingHF': break; | ||||
| 			case 'BrtListPart': break; | ||||
| 			case 'BrtMargins': break; | ||||
| 			case 'BrtOleObject': break; | ||||
| 			case 'BrtPageSetup': break; | ||||
| 			case 'BrtPane': break; | ||||
| 			case 'BrtPhoneticInfo': break; | ||||
| 			case 'BrtPrintOptions': break; | ||||
| 			case 'BrtRangeProtection': break; | ||||
| 			case 'BrtRangeProtection14': break; | ||||
| 			case 'BrtRangeProtectionIso': break; | ||||
| 			case 'BrtRangeProtectionIso14': break; | ||||
| 			case 'BrtRwDescent': break; | ||||
| 			case 'BrtSel': break; | ||||
| 			case 'BrtSheetCalcProp': break; | ||||
| 			case 'BrtSheetProtection': break; | ||||
| 			case 'BrtSheetProtectionIso': break; | ||||
| 			case 'BrtSlc': break; | ||||
| 			case 'BrtSparkline': break; | ||||
| 			case 'BrtTable': break; | ||||
| 			case 'BrtTop10Filter': break; | ||||
| 			case 'BrtUid': break; | ||||
| 			case 'BrtValueMeta': break; | ||||
| 			case 'BrtWebExtension': break; | ||||
| 			case 'BrtWsFmtInfo': break; | ||||
| 			case 'BrtWsFmtInfoEx14': break; | ||||
| 			case 'BrtWsProp': break; | ||||
| 
 | ||||
| 			case 'BrtBeginSheet': break; | ||||
| 			case 'BrtWsProp': break; // TODO
 | ||||
| 			case 'BrtSheetCalcProp': break; // TODO
 | ||||
| 			case 'BrtBeginWsViews': break; // TODO
 | ||||
| 			case 'BrtBeginWsView': break; // TODO
 | ||||
| 			case 'BrtPane': break; // TODO
 | ||||
| 			case 'BrtSel': break; // TODO
 | ||||
| 			case 'BrtEndWsView': break; // TODO
 | ||||
| 			case 'BrtEndWsViews': break; // TODO
 | ||||
| 			case 'BrtACBegin': break; // TODO
 | ||||
| 			case 'BrtRwDescent': break; // TODO
 | ||||
| 			case 'BrtACEnd': break; // TODO
 | ||||
| 			case 'BrtWsFmtInfoEx14': break; // TODO
 | ||||
| 			case 'BrtWsFmtInfo': break; // TODO
 | ||||
| 			case 'BrtBeginColInfos': break; // TODO
 | ||||
| 			case 'BrtEndColInfos': break; // TODO
 | ||||
| 			case 'BrtBeginSheetData': break; // TODO
 | ||||
| 			case 'BrtEndSheetData': break; // TODO
 | ||||
| 			case 'BrtSheetProtection': break; // TODO
 | ||||
| 			case 'BrtPrintOptions': break; // TODO
 | ||||
| 			case 'BrtMargins': break; // TODO
 | ||||
| 			case 'BrtPageSetup': break; // TODO
 | ||||
| 			case 'BrtFRTBegin': pass = true; break; | ||||
| 			case 'BrtFRTEnd': pass = false; break; | ||||
| 			case 'BrtEndSheet': break; // TODO
 | ||||
| 			case 'BrtDrawing': break; // TODO
 | ||||
| 			case 'BrtLegacyDrawing': break; // TODO
 | ||||
| 			case 'BrtLegacyDrawingHF': break; // TODO
 | ||||
| 			case 'BrtPhoneticInfo': break; // TODO
 | ||||
| 			case 'BrtBeginHeaderFooter': break; // TODO
 | ||||
| 			case 'BrtEndHeaderFooter': break; // TODO
 | ||||
| 			case 'BrtBrk': break; // TODO
 | ||||
| 			case 'BrtBeginRwBrk': break; // TODO
 | ||||
| 			case 'BrtEndRwBrk': break; // TODO
 | ||||
| 			case 'BrtBeginColBrk': break; // TODO
 | ||||
| 			case 'BrtEndColBrk': break; // TODO
 | ||||
| 			case 'BrtBeginUserShViews': break; // TODO
 | ||||
| 			case 'BrtBeginUserShView': break; // TODO
 | ||||
| 			case 'BrtEndUserShView': break; // TODO
 | ||||
| 			case 'BrtEndUserShViews': break; // TODO
 | ||||
| 			case 'BrtBkHim': break; // TODO
 | ||||
| 			case 'BrtBeginOleObjects': break; // TODO
 | ||||
| 			case 'BrtOleObject': break; // TODO
 | ||||
| 			case 'BrtEndOleObjects': break; // TODO
 | ||||
| 			case 'BrtBeginListParts': break; // TODO
 | ||||
| 			case 'BrtListPart': break; // TODO
 | ||||
| 			case 'BrtEndListParts': break; // TODO
 | ||||
| 			case 'BrtBeginSortState': break; // TODO
 | ||||
| 			case 'BrtBeginSortCond': break; // TODO
 | ||||
| 			case 'BrtEndSortCond': break; // TODO
 | ||||
| 			case 'BrtEndSortState': break; // TODO
 | ||||
| 			case 'BrtBeginConditionalFormatting': break; // TODO
 | ||||
| 			case 'BrtEndConditionalFormatting': break; // TODO
 | ||||
| 			case 'BrtBeginCFRule': break; // TODO
 | ||||
| 			case 'BrtEndCFRule': break; // TODO
 | ||||
| 			case 'BrtBeginDVals': break; // TODO
 | ||||
| 			case 'BrtDVal': break; // TODO
 | ||||
| 			case 'BrtEndDVals': break; // TODO
 | ||||
| 			case 'BrtRangeProtection': break; // TODO
 | ||||
| 			case 'BrtBeginDCon': break; // TODO
 | ||||
| 			case 'BrtEndDCon': break; // TODO
 | ||||
| 			case 'BrtBeginDRefs': break; | ||||
| 			case 'BrtDRef': break; | ||||
| 			case 'BrtEndDRefs': break; | ||||
| 			case 'BrtACBegin': break; | ||||
| 			case 'BrtACEnd': break; | ||||
| 
 | ||||
| 			/* ActiveX */ | ||||
| 			case 'BrtBeginActiveXControls': break; | ||||
| 			case 'BrtActiveX': break; | ||||
| 			case 'BrtEndActiveXControls': break; | ||||
| 
 | ||||
| 			/* AutoFilter */ | ||||
| 			case 'BrtBeginAFilter': break; | ||||
| 			case 'BrtEndAFilter': break; | ||||
| 			case 'BrtBeginFilterColumn': break; | ||||
| 			case 'BrtBeginFilters': break; | ||||
| 			case 'BrtFilter': break; | ||||
| 			case 'BrtEndFilters': break; | ||||
| 			case 'BrtEndFilterColumn': break; | ||||
| 			case 'BrtDynamicFilter': break; | ||||
| 			case 'BrtTop10Filter': break; | ||||
| 			case 'BrtBeginCustomFilters': break; | ||||
| 			case 'BrtCustomFilter': break; | ||||
| 			case 'BrtEndCustomFilters': break; | ||||
| 
 | ||||
| 			/* Smart Tags */ | ||||
| 			case 'BrtBeginSmartTags': break; | ||||
| 			case 'BrtBeginCellSmartTags': break; | ||||
| 			case 'BrtBeginCellSmartTag': break; | ||||
| 			case 'BrtCellSmartTagProperty': break; | ||||
| 			case 'BrtEndCellSmartTag': break; | ||||
| 			case 'BrtEndCellSmartTags': break; | ||||
| 			case 'BrtEndSmartTags': break; | ||||
| 
 | ||||
| 			/* Cell Watch */ | ||||
| 			case 'BrtBeginCellWatches': break; | ||||
| 			case 'BrtCellWatch': break; | ||||
| 			case 'BrtEndCellWatches': break; | ||||
| 
 | ||||
| 			/* Table */ | ||||
| 			case 'BrtTable': break; | ||||
| 
 | ||||
| 			/* Ignore Cell Errors */ | ||||
| 			case 'BrtBeginCellIgnoreECs': break; | ||||
| 			case 'BrtCellIgnoreEC': break; | ||||
| 			case 'BrtEndCellIgnoreECs': break; | ||||
| 
 | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + Record.n); | ||||
| 			default: | ||||
| 				if((Record.n||"").indexOf("Begin") > 0){} | ||||
| 				else if((Record.n||"").indexOf("End") > 0){} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + Record.n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
| @ -600,6 +573,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num | ||||
| function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = []; | ||||
| 	write_record(ba, 'BrtBeginSheetData'); | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		rr = encode_row(R); | ||||
| 		/* [ACCELLTABLE] */ | ||||
| @ -609,9 +583,10 @@ function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbo | ||||
| 			/* *16384CELL */ | ||||
| 			if(R === range.s.r) cols[C] = encode_col(C); | ||||
| 			ref = cols[C] + rr; | ||||
| 			if(!ws[ref]) continue; | ||||
| 			var cell = dense ? (ws[R]||[])[C] : ws[ref]; | ||||
| 			if(!cell) continue; | ||||
| 			/* write cell */ | ||||
| 			write_ws_bin_cell(ba, ws[ref], R, C, opts, ws); | ||||
| 			write_ws_bin_cell(ba, cell, R, C, opts, ws); | ||||
| 		} | ||||
| 	} | ||||
| 	write_record(ba, 'BrtEndSheetData'); | ||||
|  | ||||
| @ -1,5 +1,10 @@ | ||||
| RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"; | ||||
| 
 | ||||
| var CS_XML_ROOT = writextag('chartsheet', null, { | ||||
| 	'xmlns': XMLNS.main[0], | ||||
| 	'xmlns:r': XMLNS.r | ||||
| }); | ||||
| 
 | ||||
| /* 18.3 Worksheets also covers Chartsheets */ | ||||
| function parse_cs_xml(data/*:?string*/, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| @ -14,34 +19,67 @@ function parse_cs_xml(data/*:?string*/, opts, rels, wb, themes, styles)/*:Worksh | ||||
| 	if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']]; | ||||
| 	return s; | ||||
| } | ||||
| function write_cs_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ { | ||||
| 	var o = [XML_HEADER, CS_XML_ROOT]; | ||||
| 	o[o.length] = writextag("drawing", null, {"r:id": "rId1"}); | ||||
| 	add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW); | ||||
| 	if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.7 Chart Sheet */ | ||||
| function parse_cs_bin(data, opts, rels, wb, themes, styles)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| 	if(!rels) rels = {'!id':{}}; | ||||
| 	var s = {'!type':"chart", '!chart':null, '!rel':""}; | ||||
| 	var state = []; | ||||
| 	var pass = false; | ||||
| 	recordhopper(data, function cs_parse(val, Record) { | ||||
| 	recordhopper(data, function cs_parse(val, Record, RT) { | ||||
| 		switch(Record.n) { | ||||
| 
 | ||||
| 			case 'BrtDrawing': s['!rel'] = val; break; | ||||
| 
 | ||||
| 			case 'BrtBeginSheet': break; | ||||
| 			case 'BrtCsProp': break; // TODO
 | ||||
| 			case 'BrtBeginCsViews': break; // TODO
 | ||||
| 			case 'BrtBeginCsView': break; // TODO
 | ||||
| 			case 'BrtEndCsView': break; // TODO
 | ||||
| 			case 'BrtEndCsViews': break; // TODO
 | ||||
| 			case 'BrtCsProtection': break; // TODO
 | ||||
| 			case 'BrtUid': break; | ||||
| 			case 'BrtMargins': break; // TODO
 | ||||
| 			case 'BrtLegacyDrawing': break; // TODO
 | ||||
| 			case 'BrtLegacyDrawingHF': break; // TODO
 | ||||
| 			case 'BrtBkHim': break; // TODO
 | ||||
| 			case 'BrtCsProp': break; // TODO
 | ||||
| 			case 'BrtCsProtection': break; // TODO
 | ||||
| 			case 'BrtCsProtectionIso': break; // TODO
 | ||||
| 			case 'BrtCsPageSetup': break; // TODO
 | ||||
| 			case 'BrtEndSheet': break; // TODO
 | ||||
| 			case 'BrtBeginHeaderFooter': break; // TODO
 | ||||
| 			case 'BrtEndHeaderFooter': break; // TODO
 | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + Record.n); | ||||
| 
 | ||||
| 			case 'BrtFRTBegin': pass = true; break; | ||||
| 			case 'BrtFRTEnd': pass = false; break; | ||||
| 			case 'BrtACBegin': state.push(R.n); break; | ||||
| 			case 'BrtACEnd': state.pop(); break; | ||||
| 
 | ||||
| 			default: | ||||
| 				if((Record.n||"").indexOf("Begin") > 0) state.push(Record.n); | ||||
| 				else if((Record.n||"").indexOf("End") > 0) state.pop(); | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + Record.n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
| 	if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']]; | ||||
| 	return s; | ||||
| } | ||||
| function write_cs_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	var ba = buf_array(); | ||||
| 	write_record(ba, "BrtBeginSheet"); | ||||
| 	/* [BrtCsProp] */ | ||||
| 	/* CSVIEWS */ | ||||
| 	/* [[BrtCsProtectionIso] BrtCsProtection] */ | ||||
| 	/* [USERCSVIEWS] */ | ||||
| 	/* [BrtMargins] */ | ||||
| 	/* [BrtCsPageSetup] */ | ||||
| 	/* [HEADERFOOTER] */ | ||||
| 	/* BrtDrawing */ | ||||
| 	/* [BrtLegacyDrawing] */ | ||||
| 	/* [BrtLegacyDrawingHF] */ | ||||
| 	/* [BrtBkHim] */ | ||||
| 	/* [WEBPUBITEMS] */ | ||||
| 	/* FRTCHARTSHEET */ | ||||
| 	write_record(ba, "BrtEndSheet"); | ||||
| 	return ba.end(); | ||||
| } | ||||
|  | ||||
| @ -68,60 +68,61 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| 
 | ||||
| 	var Names = {}, NameList = []; | ||||
| 
 | ||||
| 	recordhopper(data, function hopper_wb(val, R) { | ||||
| 	recordhopper(data, function hopper_wb(val, R, RT) { | ||||
| 		switch(R.n) { | ||||
| 			case 'BrtBundleSh': wb.Sheets.push(val); break; | ||||
| 
 | ||||
| 			case 'BrtName': | ||||
| 				Names[val.Name] = val; NameList.push(val.Name); | ||||
| 				break; | ||||
| 			case 'BrtNameExt': break; | ||||
| 
 | ||||
| 			case 'BrtBeginBook': break; | ||||
| 			case 'BrtFileVersion': break; | ||||
| 			case 'BrtWbProp14': case 'BrtWbProp': break; | ||||
| 			case 'BrtACBegin': break; | ||||
| 			case 'BrtAbsPath15': break; | ||||
| 			case 'BrtACEnd': break; | ||||
| 			case 'BrtWbFactoid': break; | ||||
| 			/*case 'BrtBookProtectionIso': break;*/ | ||||
| 			case 'BrtBookProtection': break; | ||||
| 			case 'BrtBeginBookViews': break; | ||||
| 			case 'BrtBookProtectionIso': break; | ||||
| 			case 'BrtBookView': break; | ||||
| 			case 'BrtEndBookViews': break; | ||||
| 			case 'BrtBeginBundleShs': break; | ||||
| 			case 'BrtEndBundleShs': break; | ||||
| 			case 'BrtBeginFnGroup': break; | ||||
| 			case 'BrtEndFnGroup': break; | ||||
| 			case 'BrtBeginExternals': break; | ||||
| 			case 'BrtSupSelf': break; | ||||
| 			case 'BrtSupBookSrc': break; | ||||
| 			case 'BrtExternSheet': break; | ||||
| 			case 'BrtEndExternals': break; | ||||
| 			case 'BrtCalcProp': break; | ||||
| 			case 'BrtUserBookView': break; | ||||
| 			case 'BrtBeginPivotCacheIDs': break; | ||||
| 			case 'BrtBeginPivotCacheID': break; | ||||
| 			case 'BrtEndPivotCacheID': break; | ||||
| 			case 'BrtEndPivotCacheIDs': break; | ||||
| 			case 'BrtWebOpt': break; | ||||
| 			case 'BrtCrashRecErr': break; | ||||
| 			case 'BrtDecoupledPivotCacheID': break; | ||||
| 			case 'BrtExternSheet': break; | ||||
| 			case 'BrtFileRecover': break; | ||||
| 			case 'BrtFileSharing': break; | ||||
| 			/*case 'BrtBeginWebPubItems': break; | ||||
| 			case 'BrtBeginWebPubItem': break; | ||||
| 			case 'BrtEndWebPubItem': break; | ||||
| 			case 'BrtEndWebPubItems': break;*/ | ||||
| 
 | ||||
| 			/* Smart Tags */ | ||||
| 			case 'BrtBeginSmartTagTypes': break; | ||||
| 			case 'BrtFileSharingIso': break; | ||||
| 			case 'BrtFileVersion': break; | ||||
| 			case 'BrtFnGroup': break; | ||||
| 			case 'BrtModelRelationship': break; | ||||
| 			case 'BrtModelTable': break; | ||||
| 			case 'BrtModelTimeGroupingCalcCol': break; | ||||
| 			case 'BrtOleSize': break; | ||||
| 			case 'BrtPivotTableRef': break; | ||||
| 			case 'BrtPlaceholderName': break; | ||||
| 			case 'BrtRevisionPtr': break; | ||||
| 			case 'BrtSmartTagType': break; | ||||
| 			case 'BrtEndSmartTagTypes': break; | ||||
| 			case 'BrtSupAddin': break; | ||||
| 			case 'BrtSupBookSrc': break; | ||||
| 			case 'BrtSupSame': break; | ||||
| 			case 'BrtSupSelf': break; | ||||
| 			case 'BrtTableSlicerCacheID': break; | ||||
| 			case 'BrtTableSlicerCacheIDs': break; | ||||
| 			case 'BrtTimelineCachePivotCacheID': break; | ||||
| 			case 'BrtUid': break; | ||||
| 			case 'BrtUserBookView': break; | ||||
| 			case 'BrtWbFactoid': break; | ||||
| 			case 'BrtWbProp': break; | ||||
| 			case 'BrtWbProp14': break; | ||||
| 			case 'BrtWebOpt': break; | ||||
| 			case 'BrtWorkBookPr15': break; | ||||
| 
 | ||||
| 			case 'BrtFRTBegin': pass = true; break; | ||||
| 			case 'BrtFRTArchID$': break; | ||||
| 			case 'BrtWorkBookPr15': break; | ||||
| 			case 'BrtFRTEnd': pass = false; break; | ||||
| 			case 'BrtEndBook': break; | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n); | ||||
| 			case 'BrtACBegin': break; | ||||
| 			case 'BrtACEnd': break; | ||||
| 
 | ||||
| 			case 'BrtFRTArchID$': break; | ||||
| 			default: | ||||
| 				if((R.n||"").indexOf("Begin") > 0){} | ||||
| 				else if((R.n||"").indexOf("End") > 0){} | ||||
| 				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R.n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
|  | ||||
| @ -51,10 +51,14 @@ function write_wb(wb, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts); | ||||
| } | ||||
| 
 | ||||
| function write_ws(data/*:Worksheet*/, name/*:string*/, opts, wb/*:Workbook*/, rels) { | ||||
| function write_ws(data/*:number*/, name/*:string*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels); | ||||
| } | ||||
| 
 | ||||
| function write_cs(data/*:number*/, name/*:string*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels); | ||||
| } | ||||
| 
 | ||||
| function write_sty(data, name/*:string*/, opts) { | ||||
| 	return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts); | ||||
| } | ||||
|  | ||||
| @ -174,7 +174,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 	if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts); | ||||
| 	var Rn; | ||||
| 	var state = [], tmp; | ||||
| 	var sheets = {}, sheetnames = [], cursheet = {}, sheetname = ""; | ||||
| 	if(DENSE != null) opts.dense = DENSE; | ||||
| 	var sheets = {}, sheetnames = [], cursheet = (opts.dense ? [] : {}), sheetname = ""; | ||||
| 	var table = {}, cell = ({}/*:any*/), row = {}; | ||||
| 	var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0; | ||||
| 	var c = 0, r = 0; | ||||
| @ -199,7 +200,12 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 		case 'Cell': | ||||
| 			if(Rn[1]==='/'){ | ||||
| 				if(comments.length > 0) cell.c = comments; | ||||
| 				if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) cursheet[encode_col(c) + encode_row(r)] = cell; | ||||
| 				if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) { | ||||
| 					if(opts.dense) { | ||||
| 						if(!cursheet[r]) cursheet[r] = []; | ||||
| 						cursheet[r][c] = cell; | ||||
| 					} else cursheet[encode_col(c) + encode_row(r)] = cell; | ||||
| 				} | ||||
| 				if(cell.HRef) { | ||||
| 					cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip}; | ||||
| 					delete cell.HRef; delete cell.HRefScreenTip; | ||||
| @ -214,7 +220,12 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 					/*:: if(!cc) cc = 0; if(!rr) rr = 0; */ | ||||
| 					for(var cma = c; cma <= cc; ++cma) { | ||||
| 						for(var cmd = r; cmd <= rr; ++cmd) { | ||||
| 							if(cma > c || cmd > r) cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'}; | ||||
| 							if(cma > c || cmd > r) { | ||||
| 								if(opts.dense) { | ||||
| 									if(!cursheet[cmd]) cursheet[cmd] = []; | ||||
| 									cursheet[cmd][cma] = {t:'z'}; | ||||
| 								} else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'}; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 					c = cc + 1; | ||||
| @ -258,7 +269,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 				state.push([Rn[3], false]); | ||||
| 				tmp = xlml_parsexmltag(Rn[0]); | ||||
| 				sheetname = unescapexml(tmp.Name); | ||||
| 				cursheet = {}; | ||||
| 				cursheet = (opts.dense ? [] : {}); | ||||
| 				mergecells = []; | ||||
| 				arrayf = []; | ||||
| 				rowinfo = []; | ||||
| @ -868,6 +879,7 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo | ||||
| 		var p = col_obj_w(i, n); | ||||
| 		o.push(writextag("Column",null, {"ss:Index":i+1, "ss:Width":width2px(p.width)})); | ||||
| 	}); | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		var row = ['<Row ss:Index="' + (R+1) + '">']; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| @ -882,8 +894,8 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo | ||||
| 			} | ||||
| 			if(skip) continue; | ||||
| 			var addr = {r:R,c:C}; | ||||
| 			var ref = encode_cell(addr), cell = ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr)); | ||||
| 			var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)); | ||||
| 		} | ||||
| 		row.push("</Row>"); | ||||
| 		if(row.length > 2) o.push(row.join("")); | ||||
|  | ||||
| @ -82,7 +82,8 @@ function make_cell(val, ixfe, t)/*:any*/ { | ||||
| function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var wb = ({opts:{}}/*:any*/); | ||||
| 	var Sheets = {}; | ||||
| 	var out = {}; | ||||
| 	if(DENSE != null) options.dense = DENSE; | ||||
| 	var out = (options.dense ? [] : {}); | ||||
| 	var Directory = {}; | ||||
| 	var found_sheet = false; | ||||
| 	var range/*:Range*/ = ({}/*:any*/); | ||||
| @ -141,7 +142,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 			} | ||||
| 		} | ||||
| 		if(options.sheetRows && lastcell.r >= options.sheetRows) cell_valid = false; | ||||
| 		else out[last_cell] = line; | ||||
| 		else { | ||||
| 			if(options.dense) { | ||||
| 				if(!out[cell.r]) out[cell.r] = []; | ||||
| 				out[cell.r][cell.c] = line; | ||||
| 			} else out[last_cell] = line; | ||||
| 		} | ||||
| 	}; | ||||
| 	var opts = ({ | ||||
| 		enc: false, // encrypted
 | ||||
| @ -175,7 +181,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	/* explicit override for some broken writers */ | ||||
| 	opts.codepage = 1200; | ||||
| 	set_cp(1200); | ||||
| 
 | ||||
| 	while(blob.l < blob.length - 1) { | ||||
| 		var s = blob.l; | ||||
| 		var RecordType = blob.read_shift(2); | ||||
| @ -273,7 +278,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						Workbook.Sheets.push(wsprops); | ||||
| 					} | ||||
| 					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out; | ||||
| 					out = {}; | ||||
| 					out = options.dense ? [] : {}; | ||||
| 				} break; | ||||
| 				case 'BOF': { | ||||
| 					if(opts.biff !== 8){} | ||||
| @ -286,7 +291,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					else if(val.BIFFVer === 0x0007) opts.biff = 2; | ||||
| 					if(file_depth++) break; | ||||
| 					cell_valid = true; | ||||
| 					out = {}; | ||||
| 					out = (options.dense ? [] : {}); | ||||
| 
 | ||||
| 					if(opts.biff < 5) { | ||||
| 						if(cur_sheet === "") cur_sheet = "Sheet1"; | ||||
| @ -308,7 +313,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				} break; | ||||
| 
 | ||||
| 				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': { | ||||
| 					if(out["!type"] == "chart" && out[encode_cell({c:val.c, r:val.r})]) ++val.c; | ||||
| 					if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c; | ||||
| 					temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:'n'}; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| @ -341,7 +346,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 							var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1]; | ||||
| 							var _fe = encode_cell({r:_fr, c:_fc}); | ||||
| 							if(shared_formulae[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 							else temp_val.F = (out[_fe] || {}).F; | ||||
| 							else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F; | ||||
| 						} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 					} | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| @ -364,11 +369,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'Array': { | ||||
| 					array_formulae.push(val); | ||||
| 					var _arraystart = encode_cell(val[0].s); | ||||
| 					if(options.cellFormula && out[_arraystart]) { | ||||
| 					cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart]; | ||||
| 					if(options.cellFormula && cc) { | ||||
| 						if(!last_formula) break; /* technically unreachable */ | ||||
| 						if(!_arraystart || !out[_arraystart]) break; | ||||
| 						out[_arraystart].f = ""+stringify_formula(val[1], range, val[0], supbooks, opts); | ||||
| 						out[_arraystart].F = encode_range(val[0]); | ||||
| 						if(!_arraystart || !cc) break; | ||||
| 						cc.f = ""+stringify_formula(val[1], range, val[0], supbooks, opts); | ||||
| 						cc.F = encode_range(val[0]); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 'ShrFmla': { | ||||
| @ -378,7 +384,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						/* TODO: capture range */ | ||||
| 						if(!last_formula) break; /* technically unreachable */ | ||||
| 						shared_formulae[encode_cell(last_formula.cell)]= val[0]; | ||||
| 						(out[encode_cell(last_formula.cell)]||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts); | ||||
| 						cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)]; | ||||
| 						(cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 'LabelSst': | ||||
| @ -428,21 +435,23 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 
 | ||||
| 				case 'HLink': { | ||||
| 					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR) | ||||
| 						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) | ||||
| 							if(out[encode_cell({c:rngC,r:rngR})]) | ||||
| 								out[encode_cell({c:rngC,r:rngR})].l = val[1]; | ||||
| 						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) { | ||||
| 							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})]; | ||||
| 							if(cc) cc.l = val[1]; | ||||
| 							} | ||||
| 				} break; | ||||
| 				case 'HLinkTooltip': { | ||||
| 					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR) | ||||
| 						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) | ||||
| 							if(out[encode_cell({c:rngC,r:rngR})]) | ||||
| 								out[encode_cell({c:rngC,r:rngR})].l.Tooltip = val[1]; | ||||
| 						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) { | ||||
| 							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})]; | ||||
| 							if(cc) cc.l.Tooltip = val[1]; | ||||
| 							} | ||||
| 				} break; | ||||
| 
 | ||||
| 				/* Comments */ | ||||
| 				case 'Note': { | ||||
| 					if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */ | ||||
| 					cc = out[encode_cell(val[0])]; | ||||
| 					cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])]; | ||||
| 					var noteobj = objects[val[2]]; | ||||
| 					if(!cc) break; | ||||
| 					if(!cc.c) cc.c = []; | ||||
|  | ||||
| @ -75,21 +75,25 @@ function write_ws_biff_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:nu | ||||
| } | ||||
| 
 | ||||
| function write_biff_ws(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var dense = Array.isArray(ws); | ||||
| 	var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = []; | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		rr = encode_row(R); | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			if(R === range.s.r) cols[C] = encode_col(C); | ||||
| 			ref = cols[C] + rr; | ||||
| 			if(!ws[ref]) continue; | ||||
| 			var cell = dense ? ws[R][C] : ws[ref]; | ||||
| 			if(!cell) continue; | ||||
| 			/* write cell */ | ||||
| 			write_ws_biff_cell(ba, ws[ref], R, C, opts); | ||||
| 			write_ws_biff_cell(ba, cell, R, C, opts); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Based on test files */ | ||||
| function write_biff_buf(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) { | ||||
| 	var o = opts || {}; | ||||
| 	if(DENSE != null) o.dense = DENSE; | ||||
| 	var ba = buf_array(); | ||||
| 	var idx = 0; | ||||
| 	for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i; | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| /* TODO: in browser attach to DOM; in node use an html parser */ | ||||
| function parse_html(str/*:string*/, opts)/*:Workbook*/ { | ||||
| 	var ws/*:Worksheet*/ = ({}/*:any*/); | ||||
| function parse_html(str/*:string*/, _opts)/*:Workbook*/ { | ||||
| 	var opts = _opts || {}; | ||||
| 	if(DENSE != null) opts.dense = DENSE; | ||||
| 	var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 	var o/*:Workbook*/ = { SheetNames: ["Sheet1"], Sheets: {Sheet1:ws} }; | ||||
| 	var i = str.indexOf("<table"), j = str.indexOf("</table"); | ||||
| 	if(i == -1 || j == -1) throw new Error("Invalid HTML: missing <table> / </table> pair"); | ||||
| @ -23,10 +25,16 @@ function parse_html(str/*:string*/, opts)/*:Workbook*/ { | ||||
| 			if(range.e.r < R) range.e.r = R; | ||||
| 			if(range.s.c > C) range.s.c = C; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| 			var coord/*:string*/ = encode_cell({r:R, c:C}); | ||||
| 			/* TODO: value parsing */ | ||||
| 			if(Number(m) == Number(m)) ws[coord] = {t:'n', v:+m}; | ||||
| 			else ws[coord] = {t:'s', v:m}; | ||||
| 			if(opts.dense) { | ||||
| 				if(!ws[R]) ws[R] = []; | ||||
| 				if(Number(m) == Number(m)) ws[R][C] = {t:'n', v:+m}; | ||||
| 				else ws[R][C] = {t:'s', v:m}; | ||||
| 			} else { | ||||
| 				var coord/*:string*/ = encode_cell({r:R, c:C}); | ||||
| 				/* TODO: value parsing */ | ||||
| 				if(Number(m) == Number(m)) ws[coord] = {t:'n', v:+m}; | ||||
| 				else ws[coord] = {t:'s', v:m}; | ||||
| 			} | ||||
| 		} | ||||
| 		++R; C = 0; | ||||
| 	} | ||||
| @ -34,8 +42,10 @@ function parse_html(str/*:string*/, opts)/*:Workbook*/ { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| function parse_dom_table(table/*:HTMLElement*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 	var ws/*:Worksheet*/ = ({}/*:any*/); | ||||
| function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 	var opts = _opts || {}; | ||||
| 	if(DENSE != null) opts.dense = DENSE; | ||||
| 	var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 	var rows = table.getElementsByTagName('tr'); | ||||
| 	var range = {s:{r:0,c:0},e:{r:rows.length - 1,c:0}}; | ||||
| 	var merges = [], midx = 0; | ||||
| @ -54,7 +64,8 @@ function parse_dom_table(table/*:HTMLElement*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0) merges.push({s:{r:R,c:C},e:{r:R + RS - 1, c:C + CS - 1}}); | ||||
| 			var o = {t:'s', v:v}; | ||||
| 			if(v != null && v.length && !isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			ws[encode_cell({c:C, r:R})] = o; | ||||
| 			if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; } | ||||
| 			else ws[encode_cell({c:C, r:R})] = o; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| 			C += CS; | ||||
| 		} | ||||
|  | ||||
| @ -18,13 +18,15 @@ var parse_content_xml = (function() { | ||||
| 
 | ||||
| 	return function pcx(d/*:string*/, _opts)/*:Workbook*/ { | ||||
| 		var opts = _opts || {}; | ||||
| 		if(DENSE != null) opts.dense = DENSE; | ||||
| 		var str = xlml_normalize(d); | ||||
| 		var state/*:Array<any>*/ = [], tmp; | ||||
| 		var tag/*:: = {}*/; | ||||
| 		var NFtag = {name:""}, NF = "", pidx = 0; | ||||
| 		var sheetag/*:: = {name:"", '名称':""}*/; | ||||
| 		var rowtag/*:: = {'行号':""}*/; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {}; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = []; | ||||
| 		var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:"",c:[]}:any)*/; | ||||
| 		var ctag = {value:""}; | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/; | ||||
| @ -52,7 +54,7 @@ var parse_content_xml = (function() { | ||||
| 					sheetag = parsexmltag(Rn[0], false); | ||||
| 					R = C = -1; | ||||
| 					range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0; | ||||
| 					ws = {}; merges = []; | ||||
| 					ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = []; | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| @ -63,7 +65,10 @@ var parse_content_xml = (function() { | ||||
| 				C = -1; break; | ||||
| 			case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
 | ||||
| 				++C; | ||||
| 				if(opts.sheetStubs) ws[encode_cell({r:R,c:C})] = {t:'z'}; | ||||
| 				if(opts.sheetStubs) { | ||||
| 					if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; } | ||||
| 					else ws[encode_cell({r:R,c:C})] = {t:'z'}; | ||||
| 				} | ||||
| 				break; /* stub */ | ||||
| 			case 'table-cell': case '数据': | ||||
| 				if(Rn[0].charAt(Rn[0].length-2) === '/') { | ||||
| @ -133,8 +138,14 @@ var parse_content_xml = (function() { | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!isstub || opts.sheetStubs) { | ||||
| 						if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 							ws[encode_cell({r:R,c:C})] = q; | ||||
| 							while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q); | ||||
| 							if(opts.dense) { | ||||
| 								if(!ws[R]) ws[R] = []; | ||||
| 								ws[R][C] = q; | ||||
| 								while(--rept > 0) ws[R][++C] = dup(q); | ||||
| 							} else { | ||||
| 								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; } | ||||
|  | ||||
| @ -10,6 +10,7 @@ var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']); | ||||
| 		var marr = ws['!merges'] || [], mi = 0; | ||||
| 		var dense = Array.isArray(ws); | ||||
| 		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n'); | ||||
| 		for(; R <= range.e.r; ++R) { | ||||
| 			o.push('        <table:table-row>\n'); | ||||
| @ -26,7 +27,7 @@ var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 					break; | ||||
| 				} | ||||
| 				if(skip) { o.push(covered_cell_xml); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = ws[ref]; | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref]; | ||||
| 				var fmla = ""; | ||||
| 				if(cell && cell.f) { | ||||
| 					fmla = ' table:formula="' + escapexml(csf_to_ods_formula(cell.f)) + '"'; | ||||
|  | ||||
| @ -115,14 +115,14 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var sheetRels = ({}/*:any*/); | ||||
| 	var path, relsPath; | ||||
| 
 | ||||
| 	//if(!props.Worksheets) {
 | ||||
| 	{ | ||||
| 		var wbsheets = wb.Sheets; | ||||
| 		props.Worksheets = wbsheets.length; | ||||
| 		props.SheetNames = []; | ||||
| 		for(var j = 0; j != wbsheets.length; ++j) { | ||||
| 			props.SheetNames[j] = wbsheets[j].name; | ||||
| 		} | ||||
| 	//}
 | ||||
| 	} | ||||
| 
 | ||||
| 	var wbext = xlsb ? "bin" : "xml"; | ||||
| 	var wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels'; | ||||
|  | ||||
| @ -14,9 +14,12 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0; | ||||
| 	var wbext = opts.bookType == "xlsb" ? "bin" : "xml"; | ||||
| 	var vbafmt = opts.bookType == "xlsb" || opts.bookType == "xlsm"; | ||||
| 	var ct = { workbooks: [], sheets: [], calcchains: [], themes: [], styles: [], | ||||
| 		coreprops: [], extprops: [], custprops: [], strs:[], comments: [], vba: [], | ||||
| 		TODO:[], rels:[], xmlns: "" }; | ||||
| 	var ct = ({ | ||||
| 		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], | ||||
| 		rels:[], strs:[], comments:[], | ||||
| 		coreprops:[], extprops:[], custprops:[], themes:[], styles:[], | ||||
| 		calcchains:[], vba: [], drawings: [], | ||||
| 		TODO:[], xmlns: "" }/*:any*/); | ||||
| 	fix_write_opts(opts = opts || {}); | ||||
| 	/*:: if(!jszip) throw new Error("JSZip is not available"); */ | ||||
| 	var zip = new jszip(); | ||||
| @ -56,14 +59,24 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	add_rels(opts.rels, 1, f, RELS.WB); | ||||
| 
 | ||||
| 	for(rId=1;rId <= wb.SheetNames.length; ++rId) { | ||||
| 		f = "xl/worksheets/sheet" + rId + "." + wbext; | ||||
| 		var wsrels = {'!id':{}}; | ||||
| 		zip.file(f, write_ws(rId-1, f, opts, wb, wsrels)); | ||||
| 
 | ||||
| 		ct.sheets.push(f); | ||||
| 		add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]); | ||||
| 
 | ||||
| 		var ws = wb.Sheets[wb.SheetNames[rId-1]]; | ||||
| 		var _type = (ws || {})["!type"] || "sheet"; | ||||
| 		switch(_type) { | ||||
| 		case "chart": /* | ||||
| 			f = "xl/chartsheets/sheet" + rId + "." + wbext; | ||||
| 			zip.file(f, write_cs(rId-1, f, opts, wb, wsrels)); | ||||
| 			ct.charts.push(f); | ||||
| 			add_rels(wsrels, -1, "chartsheets/sheet" + rId + "." + wbext, RELS.CS); | ||||
| 			break; */ | ||||
| 			/* falls through */ | ||||
| 		default: | ||||
| 			f = "xl/worksheets/sheet" + rId + "." + wbext; | ||||
| 			zip.file(f, write_ws(rId-1, f, opts, wb, wsrels)); | ||||
| 			ct.sheets.push(f); | ||||
| 			add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]); | ||||
| 		} | ||||
| 
 | ||||
| 		if(ws) { | ||||
| 			var comments = ws['!comments']; | ||||
| 			if(comments && comments.length > 0) { | ||||
| @ -79,7 +92,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 			delete ws['!legacy']; | ||||
| 		} | ||||
| 
 | ||||
| 		if(wsrels['!id'].rId1) zip.file(get_rels_path(f), write_rels(wsrels)); // get_rels_path('')
 | ||||
| 		if(wsrels['!id'].rId1) zip.file(get_rels_path(f), write_rels(wsrels)); | ||||
| 	} | ||||
| 
 | ||||
| 	if(opts.Strings != null && opts.Strings.length > 0) { | ||||
| @ -111,7 +124,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	} | ||||
| 
 | ||||
| 	zip.file("[Content_Types].xml", write_ct(ct, opts)); | ||||
| 	zip.file('_rels/.rels', write_rels(opts.rels)); // get_rels_path('')
 | ||||
| 	zip.file('xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); // get_rels_path("xl/workbook." + wbext)
 | ||||
| 	zip.file('_rels/.rels', write_rels(opts.rels)); | ||||
| 	zip.file('xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); | ||||
| 	return zip; | ||||
| } | ||||
|  | ||||
| @ -94,9 +94,10 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){ | ||||
| 	var cols = new Array(r.e.c-r.s.c+1); | ||||
| 	var out = new Array(r.e.r-r.s.r-offset+1); | ||||
| 	var outi = 0; | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	for(C = r.s.c; C <= r.e.c; ++C) { | ||||
| 		cols[C] = encode_col(C); | ||||
| 		val = sheet[cols[C] + rr]; | ||||
| 		val = dense ? (sheet[r.s.r] || [])[C] : sheet[cols[C] + rr]; | ||||
| 		switch(header) { | ||||
| 			case 1: hdr[C] = C; break; | ||||
| 			case 2: hdr[C] = cols[C]; break; | ||||
| @ -120,7 +121,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/){ | ||||
| 			else row.__rowNum__ = R; | ||||
| 		} | ||||
| 		for (C = r.s.c; C <= r.e.c; ++C) { | ||||
| 			val = sheet[cols[C] + rr]; | ||||
| 			val = dense ? (sheet[R] || [])[C] : sheet[cols[C] + rr]; | ||||
| 			if(val === undefined || val.t === undefined) { | ||||
| 				if(defval === undefined) continue; | ||||
| 				if(hdr[C] != null) { row[hdr[C]] = defval; isempty = false; } | ||||
| @ -161,13 +162,14 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	var row = "", rr = "", cols = []; | ||||
| 	var i = 0, cc = 0, val; | ||||
| 	var R = 0, C = 0; | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(R = r.s.r; R <= r.e.r; ++R) { | ||||
| 		var isempty = true; | ||||
| 		row = ""; | ||||
| 		rr = encode_row(R); | ||||
| 		for(C = r.s.c; C <= r.e.c; ++C) { | ||||
| 			val = sheet[cols[C] + rr]; | ||||
| 			val = dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr]; | ||||
| 			if(val == null) txt = ""; | ||||
| 			else if(val.v != null) { | ||||
| 				isempty = false; | ||||
| @ -187,7 +189,7 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| var make_csv = sheet_to_csv; | ||||
| 
 | ||||
| function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n"; | ||||
| 	var s = sheet_to_csv(sheet, opts); | ||||
| @ -202,12 +204,13 @@ function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ { | ||||
| 	var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C; | ||||
| 	var cmds = new Array((r.e.r-r.s.r+1)*(r.e.c-r.s.c+1)); | ||||
| 	var i = 0; | ||||
| 	var dense = Array.isArray(sheet); | ||||
| 	for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 		rr = encode_row(R); | ||||
| 		for(C = r.s.c; C <= r.e.c; ++C) { | ||||
| 			y = cols[C] + rr; | ||||
| 			x = sheet[y]; | ||||
| 			x = dense ? (sheet[R]||[])[C] : sheet[y]; | ||||
| 			val = ""; | ||||
| 			if(x === undefined) continue; | ||||
| 			else if(x.F != null) { | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
| <body> | ||||
| <b>JS-XLSX Live Demo</b><br /> | ||||
| Output Format: | ||||
| <select name="format"> | ||||
| <select name="format" onchange="setfmt()"> | ||||
| <option value="csv" selected> CSV</option> | ||||
| <option value="json"> JSON</option> | ||||
| <option value="form"> FORMULAE</option> | ||||
| @ -186,7 +186,9 @@ function b64it() { | ||||
| 	process_wb(wb); | ||||
| } | ||||
| 
 | ||||
| var global_wb; | ||||
| function process_wb(wb) { | ||||
| 	global_wb = wb; | ||||
| 	var output = ""; | ||||
| 	switch(get_radio_value("format")) { | ||||
| 		case "json": | ||||
| @ -202,6 +204,7 @@ function process_wb(wb) { | ||||
| 	else out.innerText = output; | ||||
| 	if(typeof console !== 'undefined') console.log("output", new Date()); | ||||
| } | ||||
| function setfmt() {if(global_wb) process_wb(global_wb); } | ||||
| 
 | ||||
| var drop = document.getElementById('drop'); | ||||
| function handleDrop(e) { | ||||
|  | ||||
							
								
								
									
										207
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										207
									
								
								test.js
									
									
									
									
									
								
							| @ -222,19 +222,30 @@ describe('should parse test files', function() { | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| function get_cell(ws/*:Worksheet*/, addr/*:string*/) { | ||||
| 	if(!Array.isArray(ws)) return ws[addr]; | ||||
| 	var a = X.utils.decode_cell(addr); | ||||
| 	return (ws[a.r]||[])[a.c]; | ||||
| } | ||||
| 
 | ||||
| function each_cell(ws, f) { | ||||
| 	if(Array.isArray(ws)) ws.forEach(function(row) { if(row) row.forEach(f); }); | ||||
| 	else Object.keys(ws).forEach(function(addr) { if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; f(ws[addr]); }); | ||||
| } | ||||
| 
 | ||||
| /* comments_stress_test family */ | ||||
| function check_comments(wb) { | ||||
| 	var ws0 = wb.Sheets.Sheet2; | ||||
| 	assert.equal(ws0.A1.c[0].a, 'Author'); | ||||
| 	assert.equal(ws0.A1.c[0].t, 'Author:\nGod thinks this is good'); | ||||
| 	assert.equal(ws0.C1.c[0].a, 'Author'); | ||||
| 	assert.equal(ws0.C1.c[0].t, 'I really hope that xlsx decides not to use magic like rPr'); | ||||
| 	assert.equal(get_cell(ws0,"A1").c[0].a, 'Author'); | ||||
| 	assert.equal(get_cell(ws0,"A1").c[0].t, 'Author:\nGod thinks this is good'); | ||||
| 	assert.equal(get_cell(ws0,"C1").c[0].a, 'Author'); | ||||
| 	assert.equal(get_cell(ws0,"C1").c[0].t, 'I really hope that xlsx decides not to use magic like rPr'); | ||||
| 
 | ||||
| 	var ws3 = wb.Sheets.Sheet4; | ||||
| 	assert.equal(ws3.B1.c[0].a, 'Author'); | ||||
| 	assert.equal(ws3.B1.c[0].t, 'The next comment is empty'); | ||||
| 	assert.equal(ws3.B2.c[0].a, 'Author'); | ||||
| 	assert.equal(ws3.B2.c[0].t, ''); | ||||
| 	assert.equal(get_cell(ws3,"B1").c[0].a, 'Author'); | ||||
| 	assert.equal(get_cell(ws3,"B1").c[0].t, 'The next comment is empty'); | ||||
| 	assert.equal(get_cell(ws3,"B2").c[0].a, 'Author'); | ||||
| 	assert.equal(get_cell(ws3,"B2").c[0].t, ''); | ||||
| } | ||||
| 
 | ||||
| describe('parse options', function() { | ||||
| @ -248,17 +259,15 @@ describe('parse options', function() { | ||||
| 		it('XLSX should generate HTML by default', function() { | ||||
| 			var wb = X.readFile(paths.cstxlsx); | ||||
| 			var ws = wb.Sheets.Sheet1; | ||||
| 			Object.keys(ws).forEach(function(addr) { | ||||
| 				if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 				assert(html_cell_types.indexOf(ws[addr].t) === -1 || ws[addr].h); | ||||
| 			each_cell(ws, function(cell) { | ||||
| 				assert(html_cell_types.indexOf(cell.t) === -1 || cell.h); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('XLSX should not generate HTML when requested', function() { | ||||
| 			var wb = X.readFile(paths.cstxlsx, {cellHTML:false}); | ||||
| 			var ws = wb.Sheets.Sheet1; | ||||
| 			Object.keys(ws).forEach(function(addr) { | ||||
| 				if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 				assert(typeof ws[addr].h === 'undefined'); | ||||
| 			each_cell(ws, function(cell) { | ||||
| 				assert(typeof cell.h === 'undefined'); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should generate formulae by default', function() { | ||||
| @ -267,9 +276,8 @@ describe('parse options', function() { | ||||
| 				var found = false; | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					Object.keys(ws).forEach(function(addr) { | ||||
| 						if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 						if(typeof ws[addr].f !== 'undefined') return (found = true); | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						if(typeof cell.f !== 'undefined') return (found = true); | ||||
| 					}); | ||||
| 				}); | ||||
| 				assert(found); | ||||
| @ -280,98 +288,95 @@ describe('parse options', function() { | ||||
| 				var wb =X.readFile(p,{cellFormula:false}); | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					Object.keys(ws).forEach(function(addr) { | ||||
| 						if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 						assert(typeof ws[addr].f === 'undefined'); | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						assert(typeof cell.f === 'undefined'); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should not generate number formats by default', function() { | ||||
| 			[paths.nfxls, paths.nfxlsx].forEach(function(p) { | ||||
| 			[paths.nfxls, paths.nfxlsx, paths.nfxlsb].forEach(function(p) { | ||||
| 				var wb = X.readFile(p); | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					Object.keys(ws).forEach(function(addr) { | ||||
| 						if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 						assert(typeof ws[addr].z === 'undefined'); | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						assert(typeof cell.z === 'undefined'); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should generate number formats when requested', function() { | ||||
| 			[paths.nfxls, paths.nfxlsx].forEach(function(p) { | ||||
| 			[paths.nfxls, paths.nfxlsx, paths.nfxlsb].forEach(function(p) { | ||||
| 				var wb = X.readFile(p, {cellNF: true}); | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					Object.keys(ws).forEach(function(addr) { | ||||
| 						if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 						assert(ws[addr].t!== 'n' || typeof ws[addr].z !== 'undefined'); | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						assert(cell.t!== 'n' || typeof cell.z !== 'undefined'); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should not generate cell styles by default', function() { | ||||
| 			[paths.cssxlsx, paths.cssxls, paths.cssxml].forEach(function(p) { | ||||
| 			var wb = X.readFile(p); | ||||
| 			wb.SheetNames.forEach(function(s) { | ||||
| 				var ws = wb.Sheets[s]; | ||||
| 				Object.keys(ws).forEach(function(addr) { | ||||
| 					if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 					assert(typeof ws[addr].s === 'undefined'); | ||||
| 			[paths.cssxlsx, paths.cssxlsb, paths.cssxls, paths.cssxml].forEach(function(p) { | ||||
| 				var wb = X.readFile(p); | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						assert(typeof cell.s === 'undefined'); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should generate cell styles when requested', function() { | ||||
| 			/* TODO: XLS / XLML */ | ||||
| 			[paths.cssxlsx /*,paths.cssxls, paths.cssxml*/].forEach(function(p) { | ||||
| 			var wb = X.readFile(p, {cellStyles:true}); | ||||
| 			var found = false; | ||||
| 			wb.SheetNames.forEach(function(s) { | ||||
| 				var ws = wb.Sheets[s]; | ||||
| 				Object.keys(ws).forEach(function(addr) { | ||||
| 					if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 					if(typeof ws[addr].s !== 'undefined') return (found = true); | ||||
| 			[paths.cssxlsx /*, paths.cssxlsb, paths.cssxls, paths.cssxml*/].forEach(function(p) { | ||||
| 				var wb = X.readFile(p, {cellStyles:true}); | ||||
| 				var found = false; | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						if(typeof cell.s !== 'undefined') return (found = true); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 			assert(found); | ||||
| 				assert(found); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should not generate cell dates by default', function() { | ||||
| 			var wb = X.readFile(paths.dtxlsx); | ||||
| 			wb.SheetNames.forEach(function(s) { | ||||
| 				var ws = wb.Sheets[s]; | ||||
| 				Object.keys(ws).forEach(function(addr) { | ||||
| 					if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 					assert(ws[addr].t !== 'd'); | ||||
| 			[paths.dtxlsx, paths.dtxlsb, paths.dtxls, paths.dtxml].forEach(function(p) { | ||||
| 				var wb = X.readFile(p); | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						assert(cell.t !== 'd'); | ||||
| 					}); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('XLSX should generate cell dates when requested', function() { | ||||
| 			var wb = X.readFile(paths.dtxlsx, {cellDates: true}); | ||||
| 			var found = false; | ||||
| 			wb.SheetNames.forEach(function(s) { | ||||
| 				var ws = wb.Sheets[s]; | ||||
| 				Object.keys(ws).forEach(function(addr) { | ||||
| 					if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; | ||||
| 					if(ws[addr].t === 'd') return (found = true); | ||||
| 			[paths.dtxlsx, paths.dtxlsb, paths.dtxls, paths.dtxml].forEach(function(p) { | ||||
| 				var wb = X.readFile(paths.dtxlsx, {cellDates: true}); | ||||
| 				var found = false; | ||||
| 				wb.SheetNames.forEach(function(s) { | ||||
| 					var ws = wb.Sheets[s]; | ||||
| 					each_cell(ws, function(cell) { | ||||
| 						if(cell.t === 'd') return (found = true); | ||||
| 					}); | ||||
| 				}); | ||||
| 				assert(found); | ||||
| 			}); | ||||
| 			assert(found); | ||||
| 		}); | ||||
| 	}); | ||||
| 	describe('sheet', function() { | ||||
| 		it('should not generate sheet stubs by default', function() { | ||||
| 			[paths.mcxlsx, paths.mcxlsb, paths.mcods, paths.mcxls, paths.mcxml].forEach(function(p) { | ||||
| 				var wb = X.readFile(p); | ||||
| 				assert.throws(function() { return wb.Sheets.Merge.A2.v; }); | ||||
| 				assert.throws(function() { return get_cell(wb.Sheets.Merge, "A2").v; }); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should generate sheet stubs when requested', function() { | ||||
| 			[paths.mcxlsx, paths.mcxlsb, paths.mcods, paths.mcxls, paths.mcxml].forEach(function(p) { | ||||
| 				var wb = X.readFile(p, {sheetStubs:true}); | ||||
| 				assert(wb.Sheets.Merge.A2.t == 'z'); | ||||
| 				assert(get_cell(wb.Sheets.Merge, "A2").t == 'z'); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should handle stub cells', function() { | ||||
| @ -384,10 +389,10 @@ describe('parse options', function() { | ||||
| 			}); | ||||
| 		}); | ||||
| 		function checkcells(wb, A46, B26, C16, D2) { | ||||
| 			assert((typeof wb.Sheets.Text.A46 !== 'undefined') == A46); | ||||
| 			assert((typeof wb.Sheets.Text.B26 !== 'undefined') == B26); | ||||
| 			assert((typeof wb.Sheets.Text.C16 !== 'undefined') == C16); | ||||
| 			assert((typeof wb.Sheets.Text.D2  !== 'undefined') == D2); | ||||
| 			assert((typeof get_cell(wb.Sheets.Text, "A46") !== 'undefined') == A46); | ||||
| 			assert((typeof get_cell(wb.Sheets.Text, "B26") !== 'undefined') == B26); | ||||
| 			assert((typeof get_cell(wb.Sheets.Text, "C16") !== 'undefined') == C16); | ||||
| 			assert((typeof get_cell(wb.Sheets.Text, "D2")  !== 'undefined') == D2); | ||||
| 		} | ||||
| 		it('should read all cells by default', function() { | ||||
| 			[paths.fstxlsx, paths.fstxlsb, paths.fstods, paths.fstxls, paths.fstxml].forEach(function(p) { | ||||
| @ -604,7 +609,7 @@ var stykeys = [ | ||||
| 	"bgColor.rgb" | ||||
| ]; | ||||
| function diffsty(ws, r1,r2) { | ||||
| 	var c1 = ws[r1].s, c2 = ws[r2].s; | ||||
| 	var c1 = get_cell(ws,r1).s, c2 = get_cell(ws,r2).s; | ||||
| 	stykeys.forEach(function(m) { | ||||
| 		var c = -1; | ||||
| 		if(styexc.indexOf(r1+"|"+r2+"|"+m) > -1) c = 1; | ||||
| @ -615,14 +620,14 @@ function diffsty(ws, r1,r2) { | ||||
| 
 | ||||
| function hlink(wb) { | ||||
| 	var ws = wb.Sheets.Sheet1; | ||||
| 	assert.equal(ws.A1.l.Target, "http://www.sheetjs.com"); | ||||
| 	assert.equal(ws.A2.l.Target, "http://oss.sheetjs.com"); | ||||
| 	assert.equal(ws.A3.l.Target, "http://oss.sheetjs.com#foo"); | ||||
| 	assert.equal(ws.A4.l.Target, "mailto:dev@sheetjs.com"); | ||||
| 	assert.equal(ws.A5.l.Target, "mailto:dev@sheetjs.com?subject=hyperlink"); | ||||
| 	assert.equal(ws.A6.l.Target, "../../sheetjs/Documents/Test.xlsx"); | ||||
| 	assert.equal(ws.A7.l.Target, "http://sheetjs.com"); | ||||
| 	assert.equal(ws.A7.l.Tooltip, "foo bar baz"); | ||||
| 	assert.equal(get_cell(ws, "A1").l.Target, "http://www.sheetjs.com"); | ||||
| 	assert.equal(get_cell(ws, "A2").l.Target, "http://oss.sheetjs.com"); | ||||
| 	assert.equal(get_cell(ws, "A3").l.Target, "http://oss.sheetjs.com#foo"); | ||||
| 	assert.equal(get_cell(ws, "A4").l.Target, "mailto:dev@sheetjs.com"); | ||||
| 	assert.equal(get_cell(ws, "A5").l.Target, "mailto:dev@sheetjs.com?subject=hyperlink"); | ||||
| 	assert.equal(get_cell(ws, "A6").l.Target, "../../sheetjs/Documents/Test.xlsx"); | ||||
| 	assert.equal(get_cell(ws, "A7").l.Target, "http://sheetjs.com"); | ||||
| 	assert.equal(get_cell(ws, "A7").l.Tooltip, "foo bar baz"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -668,12 +673,12 @@ describe('parse features', function() { | ||||
| 			var wb4=X.readFile(paths.swcxml); | ||||
| 
 | ||||
| 			[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) { | ||||
| 				assert.equal(ws.B1.c.length, 1,"must have 1 comment"); | ||||
| 				assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author"); | ||||
| 				assert.equal(ws.B1.c[0].t, "Yegor Kozlov:\nfirst cell", "must have the concatenated texts"); | ||||
| 				assert.equal(get_cell(ws, "B1").c.length, 1,"must have 1 comment"); | ||||
| 				assert.equal(get_cell(ws, "B1").c[0].a, "Yegor Kozlov","must have the same author"); | ||||
| 				assert.equal(get_cell(ws, "B1").c[0].t, "Yegor Kozlov:\nfirst cell", "must have the concatenated texts"); | ||||
| 				if(i > 0) return; | ||||
| 				assert.equal(ws.B1.c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation"); | ||||
| 				assert.equal(ws.B1.c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation"); | ||||
| 				assert.equal(get_cell(ws, "B1").c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation"); | ||||
| 				assert.equal(get_cell(ws, "B1").c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation"); | ||||
| 			}); | ||||
| 		}); | ||||
| 		[ | ||||
| @ -686,10 +691,10 @@ describe('parse features', function() { | ||||
| 			var wb = X.readFile(m[1]); | ||||
| 			check_comments(wb); | ||||
| 			var ws0 = wb.Sheets.Sheet2; | ||||
| 			assert.equal(ws0.A1.c[0].a, 'Author'); | ||||
| 			assert.equal(ws0.A1.c[0].t, 'Author:\nGod thinks this is good'); | ||||
| 			assert.equal(ws0.C1.c[0].a, 'Author'); | ||||
| 			assert.equal(ws0.C1.c[0].t, 'I really hope that xlsx decides not to use magic like rPr'); | ||||
| 			assert.equal(get_cell(ws0,"A1").c[0].a, 'Author'); | ||||
| 			assert.equal(get_cell(ws0,"A1").c[0].t, 'Author:\nGod thinks this is good'); | ||||
| 			assert.equal(get_cell(ws0,"C1").c[0].a, 'Author'); | ||||
| 			assert.equal(get_cell(ws0,"C1").c[0].t, 'I really hope that xlsx decides not to use magic like rPr'); | ||||
| 		}); }); | ||||
| 	}); | ||||
| 
 | ||||
| @ -871,15 +876,15 @@ describe('parse features', function() { | ||||
| 			var wb, ws; | ||||
| 			wb = X.readFile(f[1]); | ||||
| 			ws = wb.Sheets[f[2]]; | ||||
| 			assert.equal(ws[f[3]].w, f[4]); | ||||
| 			assert.equal(ws[f[3]].t, 'n'); | ||||
| 			assert.equal(get_cell(ws, f[3]).w, f[4]); | ||||
| 			assert.equal(get_cell(ws, f[3]).t, 'n'); | ||||
| 		}); }); | ||||
| 		it('should generate date cells if cellDates is true', function() { fmts.forEach(function(f) { | ||||
| 			var wb, ws; | ||||
| 			wb = X.readFile(f[1], {cellDates:true}); | ||||
| 			ws = wb.Sheets[f[2]]; | ||||
| 			assert.equal(ws[f[3]].w, f[4]); | ||||
| 			assert.equal(ws[f[3]].t, 'd'); | ||||
| 			assert.equal(get_cell(ws, f[3]).w, f[4]); | ||||
| 			assert.equal(get_cell(ws, f[3]).t, 'd'); | ||||
| 		}); }); | ||||
| 	}); | ||||
| 
 | ||||
| @ -931,8 +936,8 @@ describe('parse features', function() { | ||||
| 			  bgColor: { theme: 7, raw_rgb: '8064A2' } } | ||||
| 		]; | ||||
| 		ranges.forEach(function(rng) { | ||||
| 			it('XLS  | ' + rng,function(){cmparr(rn2(rng).map(function(x){ return wsxls[x].s; }));}); | ||||
| 			it('XLSX | ' + rng,function(){cmparr(rn2(rng).map(function(x){ return wsxlsx[x].s; }));}); | ||||
| 			it('XLS  | ' + rng,function(){cmparr(rn2(rng).map(function(x){ return get_cell(wsxls,x).s; }));}); | ||||
| 			it('XLSX | ' + rng,function(){cmparr(rn2(rng).map(function(x){ return get_cell(wsxlsx,x).s; }));}); | ||||
| 		}); | ||||
| 		it('different styles', function() { | ||||
| 			for(var i = 0; i != ranges.length-1; ++i) { | ||||
| @ -944,8 +949,8 @@ describe('parse features', function() { | ||||
| 			} | ||||
| 		}); | ||||
| 		it('correct styles', function() { | ||||
| 			var stylesxls = ranges.map(function(r) { return rn2(r)[0]; }).map(function(r) { return wsxls[r].s; }); | ||||
| 			var stylesxlsx = ranges.map(function(r) { return rn2(r)[0]; }).map(function(r) { return wsxlsx[r].s; }); | ||||
| 			var stylesxls = ranges.map(function(r) { return rn2(r)[0]; }).map(function(r) { return get_cell(wsxls,r).s; }); | ||||
| 			var stylesxlsx = ranges.map(function(r) { return rn2(r)[0]; }).map(function(r) { return get_cell(wsxlsx,r).s; }); | ||||
| 			for(var i = 0; i != exp.length; ++i) { | ||||
| 				[ | ||||
| 					"fgColor.theme","fgColor.raw_rgb", | ||||
| @ -1023,7 +1028,7 @@ describe('roundtrip features', function() { | ||||
| 				var wb1 = X.readFile(f, {cellNF: true, cellDates: di, WTF: opts.WTF}); | ||||
| 				var  _f = X.write(wb1, {type:'binary', cellDates:dj, WTF:opts.WTF}); | ||||
| 				var wb2 = X.read(_f, {type:'binary', cellDates: dk, WTF: opts.WTF}); | ||||
| 				var m = [wb1,wb2].map(function(x) { return x.Sheets[sheet][addr]; }); | ||||
| 				var m = [wb1,wb2].map(function(x) { return get_cell(x.Sheets[sheet], addr); }); | ||||
| 				assert.equal(m[0].w, m[1].w); | ||||
| 
 | ||||
| 				assert.equal(m[0].t, b); | ||||
| @ -1320,8 +1325,8 @@ describe('csv output', function() { | ||||
| 	it('should handle dateNF', function() { | ||||
| 		var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,20140219,0.3\n,,,\nbaz,,qux,\n"; | ||||
| 		var _ws =  X.utils.aoa_to_sheet(data, {cellDates:true}); | ||||
| 		delete _ws.C3.w; | ||||
| 		delete _ws.C3.z; | ||||
| 		delete get_cell(_ws,"C3").w; | ||||
| 		delete get_cell(_ws,"C3").z; | ||||
| 		assert.equal(baseline, X.utils.sheet_to_csv(_ws, {dateNF:"YYYYMMDD"})); | ||||
| 	}); | ||||
| 	it('should handle strip', function() { | ||||
| @ -1349,8 +1354,8 @@ describe('js -> file -> js', function() { | ||||
| 	if(typeof before != 'undefined') before(bef); | ||||
| 	else it('before', bef); | ||||
| 	function eqcell(wb1, wb2, s, a) { | ||||
| 		assert.equal(wb1.Sheets[s][a].v, wb2.Sheets[s][a].v); | ||||
| 		assert.equal(wb1.Sheets[s][a].t, wb2.Sheets[s][a].t); | ||||
| 		assert.equal(get_cell(wb1.Sheets[s], a).v, get_cell(wb2.Sheets[s], a).v); | ||||
| 		assert.equal(get_cell(wb1.Sheets[s], a).t, get_cell(wb2.Sheets[s], a).t); | ||||
| 	} | ||||
| 	ofmt.forEach(function(f) { | ||||
| 		it(f, function() { | ||||
| @ -1386,9 +1391,9 @@ describe('corner cases', function() { | ||||
| 			["baz", null, "q\"ux"] | ||||
| 		]; | ||||
| 		var ws = X.utils.aoa_to_sheet(data); | ||||
| 		ws.A1.f = ""; ws.A1.w = ""; | ||||
| 		delete ws.C3.w; delete ws.C3.z; ws.C3.XF = {ifmt:14}; | ||||
| 		ws.A4.t = "e"; | ||||
| 		get_cell(ws,"A1").f = ""; get_cell(ws,"A1").w = ""; | ||||
| 		delete get_cell(ws,"C3").w; delete get_cell(ws,"C3").z; get_cell(ws,"C3").XF = {ifmt:14}; | ||||
| 		get_cell(ws,"A4").t = "e"; | ||||
| 		X.utils.get_formulae(ws); | ||||
| 		X.utils.make_csv(ws); | ||||
| 		X.utils.make_json(ws); | ||||
| @ -1400,7 +1405,7 @@ describe('corner cases', function() { | ||||
| 		X.write(wb, {type: "base64", bookType: 'xlsb'}); | ||||
| 		X.write(wb, {type: "binary", bookType: 'ods'}); | ||||
| 		X.write(wb, {type: "binary", bookType: 'biff2'}); | ||||
| 		ws.A2.t = "f"; | ||||
| 		get_cell(ws,"A2").t = "f"; | ||||
| 		assert.throws(function() { X.utils.make_json(ws); }); | ||||
| 	}); | ||||
| 	it('SSF', function() { | ||||
|  | ||||
							
								
								
									
										758
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										758
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user