forked from sheetjs/sheetjs
		
	sheet visibility
- XLSB read V H VH + write V H VH - XLSX read V H VH + write V H VH - XLML read V H VH + write V H VH - XLS read V H VH - fixes #123 h/t @rla-dev @Mior - fixes #464 h/t @enobufs @thowk - fixes #498 h/t @digity - fixes #503 h/t @digity
This commit is contained in:
		
							parent
							
								
									233eae2f4e
								
							
						
					
					
						commit
						97f7c1d4bf
					
				
							
								
								
									
										32
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										32
									
								
								README.md
									
									
									
									
									
								
							| @ -44,6 +44,7 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
|     + [Formulae](#formulae) | ||||
|     + [Column Properties](#column-properties) | ||||
|     + [Hyperlinks](#hyperlinks) | ||||
|     + [Sheet Visibility](#sheet-visibility) | ||||
| - [Parsing Options](#parsing-options) | ||||
|   * [Input Type](#input-type) | ||||
|   * [Guessing File Type](#guessing-file-type) | ||||
| @ -714,6 +715,37 @@ ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" }; | ||||
| Note that Excel does not automatically style hyperlinks -- they will generally | ||||
| be displayed as normal text. | ||||
| 
 | ||||
| #### Sheet Visibility | ||||
| 
 | ||||
| Excel enables hiding sheets in the lower tab bar.  The sheet data is stored in | ||||
| the file but the UI does not readily make it available.  Standard hidden sheets | ||||
| are revealed in the unhide menu.  Excel also has "very hidden" sheets which | ||||
| cannot be revealed in the menu.  It is only accessible in the VB Editor! | ||||
| 
 | ||||
| The visibility setting is stored in the `Hidden` property of the sheet props | ||||
| array.  The values are: | ||||
| 
 | ||||
| | Value | Definition  | | ||||
| |:-----:|:------------| | ||||
| |   0   | Visible     | | ||||
| |   1   | Hidden      | | ||||
| |   2   | Very Hidden | | ||||
| 
 | ||||
| With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>: | ||||
| 
 | ||||
| ```js | ||||
| > wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] }) | ||||
| [ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ] | ||||
| ``` | ||||
| 
 | ||||
| Non-Excel formats do not support the Very Hidden state.  The best way to test | ||||
| if a sheet is visible is to check if the `Hidden` property is logical negation: | ||||
| 
 | ||||
| ```js | ||||
| > wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] }) | ||||
| [ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ] | ||||
| ``` | ||||
| 
 | ||||
| ## Parsing Options | ||||
| 
 | ||||
| The exported `read` and `readFile` functions accept an options argument: | ||||
|  | ||||
| @ -179,6 +179,7 @@ function prep_blob(blob, pos/*:number*/) { | ||||
| } | ||||
| 
 | ||||
| function parsenoop(blob, length/*:number*/) { blob.l += length; } | ||||
| function parsenooplog(blob, length/*:number*/) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; } | ||||
| 
 | ||||
| function writenoop(blob, length/*:number*/) { blob.l += length; } | ||||
| 
 | ||||
|  | ||||
| @ -35,8 +35,8 @@ function parse_ext_props(data, p) { | ||||
| 		var v = parseVector(q.HeadingPairs); | ||||
| 		var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; }); | ||||
| 		var idx = 0, len = 0; | ||||
| 		for(var i = 0; i !== v.length; ++i) { | ||||
| 			len = +(v[++i].v); | ||||
| 		for(var i = 0; i !== v.length; i+=2) { | ||||
| 			len = +(v[i+1].v); | ||||
| 			switch(v[i].v) { | ||||
| 				case "Worksheets": | ||||
| 				case "工作表": | ||||
| @ -69,6 +69,7 @@ function parse_ext_props(data, p) { | ||||
| 			idx += len; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -303,7 +303,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook | ||||
| 			if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell); | ||||
| 		} | ||||
| 		if(r.length > 0) { | ||||
| 			var params = {r:rr} | ||||
| 			var params = ({r:rr}/*:any*/); | ||||
| 			if(rows && rows[R]) { | ||||
| 				var row = rows[R]; | ||||
| 				if(row.hidden) params.hidden = 1; | ||||
|  | ||||
| @ -37,7 +37,7 @@ var WBViewDef = [ | ||||
| 
 | ||||
| /* 18.2.19 (CT_Sheet) Defaults */ | ||||
| var SheetDef = [ | ||||
| 	['state', 'visible'] | ||||
| 	//['state', 'visible']
 | ||||
| ]; | ||||
| 
 | ||||
| /* 18.2.2  (CT_CalcPr) Defaults */ | ||||
|  | ||||
| @ -43,7 +43,15 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 			/* 18.2.20 sheets CT_Sheets 1 */ | ||||
| 			case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			/* 18.2.19   sheet CT_Sheet + */ | ||||
| 			case '<sheet': delete y[0]; y.name = unescapexml(utf8read(y.name)); wb.Sheets.push(y); break; | ||||
| 			case '<sheet': | ||||
| 				switch(y.state) { | ||||
| 					case "hidden": y.Hidden = 1; break; | ||||
| 					case "veryHidden": y.Hidden = 2; break; | ||||
| 					default: y.Hidden = 0; | ||||
| 				} | ||||
| 				delete y.state; | ||||
| 				y.name = unescapexml(utf8read(y.name)); | ||||
| 				delete y[0]; wb.Sheets.push(y); break; | ||||
| 			case '</sheet>': break; | ||||
| 
 | ||||
| 			/* 18.2.15 functionGroups CT_FunctionGroups ? */ | ||||
| @ -153,8 +161,17 @@ function write_wb_xml(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:string*/ { | ||||
| 	o[o.length] = WB_XML_ROOT; | ||||
| 	o[o.length] = (writextag('workbookPr', null, {date1904:safe1904(wb), codeName:"ThisWorkbook"})); | ||||
| 	o[o.length] = "<sheets>"; | ||||
| 	for(var i = 0; i != wb.SheetNames.length; ++i) | ||||
| 		o[o.length] = (writextag('sheet',null,{name:escapexml(wb.SheetNames[i].substr(0,31)), sheetId:""+(i+1), "r:id":"rId"+(i+1)})); | ||||
| 	var sheets = wb.Workbook && wb.Workbook.Sheets || []; | ||||
| 	for(var i = 0; i != wb.SheetNames.length; ++i) { | ||||
| 		var sht = ({name:escapexml(wb.SheetNames[i].substr(0,31))}/*:any*/); | ||||
| 		sht.sheetId = ""+(i+1); | ||||
| 		sht["r:id"] = "rId"+(i+1); | ||||
| 		if(sheets[i]) switch(sheets[i].Hidden) { | ||||
| 			case 1: sht.state = "hidden"; break; | ||||
| 			case 2: sht.state = "veryHidden"; break; | ||||
| 		} | ||||
| 		o[o.length] = (writextag('sheet',null,sht)); | ||||
| 	} | ||||
| 	o[o.length] = "</sheets>"; | ||||
| 	if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| /* [MS-XLSB] 2.4.301 BrtBundleSh */ | ||||
| function parse_BrtBundleSh(data, length/*:number*/) { | ||||
| 	var z = {}; | ||||
| 	z.hsState = data.read_shift(4); //ST_SheetState
 | ||||
| 	z.Hidden = data.read_shift(4); //hsState ST_SheetState
 | ||||
| 	z.iTabID = data.read_shift(4); | ||||
| 	z.strRelID = parse_RelID(data,length-8); | ||||
| 	z.name = parse_XLWideString(data); | ||||
| @ -9,7 +9,7 @@ function parse_BrtBundleSh(data, length/*:number*/) { | ||||
| } | ||||
| function write_BrtBundleSh(data, o) { | ||||
| 	if(!o) o = new_buf(127); | ||||
| 	o.write_shift(4, data.hsState); | ||||
| 	o.write_shift(4, data.Hidden); | ||||
| 	o.write_shift(4, data.iTabID); | ||||
| 	write_RelID(data.strRelID, o); | ||||
| 	write_XLWideString(data.name.substr(0,31), o); | ||||
| @ -138,7 +138,8 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| function write_BUNDLESHS(ba, wb, opts) { | ||||
| 	write_record(ba, "BrtBeginBundleShs"); | ||||
| 	for(var idx = 0; idx != wb.SheetNames.length; ++idx) { | ||||
| 		var d = { hsState: 0, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0; | ||||
| 		var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		write_record(ba, "BrtBundleSh", write_BrtBundleSh(d)); | ||||
| 	} | ||||
| 	write_record(ba, "BrtEndBundleShs"); | ||||
| @ -156,9 +157,34 @@ function write_BrtFileVersion(data, o) { | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.298 BrtBookView */ | ||||
| function write_BrtBookView(idx, o) { | ||||
| 	if(!o) o = new_buf(29); | ||||
| 	o.write_shift(-4, 0); | ||||
| 	o.write_shift(-4, 460); | ||||
| 	o.write_shift(4,  28800); | ||||
| 	o.write_shift(4,  17600); | ||||
| 	o.write_shift(4,  500); | ||||
| 	o.write_shift(4,  idx); | ||||
| 	o.write_shift(4,  idx); | ||||
| 	var flags = 0x78; | ||||
| 	o.write_shift(1,  flags); | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.60 Workbook */ | ||||
| function write_BOOKVIEWS(ba, wb, opts) { | ||||
| 	/* required if hidden tab appears before visible tab */ | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) return; | ||||
| 	var sheets = wb.Workbook.Sheets; | ||||
| 	var i = 0, vistab = -1, hidden = -1; | ||||
| 	for(; i < sheets.length; ++i) { | ||||
| 		if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i; | ||||
| 		else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i; | ||||
| 	} | ||||
| 	if(hidden > vistab) return; | ||||
| 	write_record(ba, "BrtBeginBookViews"); | ||||
| 	write_record(ba, "BrtBookView", write_BrtBookView(vistab)); | ||||
| 	/* 1*(BrtBookView *FRT) */ | ||||
| 	write_record(ba, "BrtEndBookViews"); | ||||
| } | ||||
| @ -192,7 +218,7 @@ function write_wb_bin(wb, opts) { | ||||
| 	write_record(ba, "BrtWbProp", write_BrtWbProp()); | ||||
| 	/* [ACABSPATH] */ | ||||
| 	/* [[BrtBookProtectionIso] BrtBookProtection] */ | ||||
| 	/* write_BOOKVIEWS(ba, wb, opts); */ | ||||
| 	write_BOOKVIEWS(ba, wb, opts); | ||||
| 	write_BUNDLESHS(ba, wb, opts); | ||||
| 	/* [FNGROUP] */ | ||||
| 	/* [EXTERNALS] */ | ||||
|  | ||||
| @ -186,6 +186,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 	var cstys = [], csty, seencol = false; | ||||
| 	var arrayf = []; | ||||
| 	var rowinfo = []; | ||||
| 	var Workbook = { Sheets:[] }, wsprops = {}; | ||||
| 	xlmlregex.lastIndex = 0; | ||||
| 	str = str.replace(/<!--([^\u2603]*?)-->/mg,""); | ||||
| 	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| @ -260,6 +261,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 				mergecells = []; | ||||
| 				arrayf = []; | ||||
| 				rowinfo = []; | ||||
| 				wsprops = {name:sheetname, Hidden:0}; | ||||
| 				Workbook.Sheets.push(wsprops); | ||||
| 			} | ||||
| 			break; | ||||
| 		case 'Table': | ||||
| @ -484,8 +487,15 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 
 | ||||
| 				/* WorksheetOptions */ | ||||
| 				case 'WorksheetOptions': switch(Rn[3]) { | ||||
| 					case 'Visible': | ||||
| 						if(Rn[0].slice(-2) === "/>"){} | ||||
| 						else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) { | ||||
| 							case "SheetHidden": wsprops.Hidden = 1; break; | ||||
| 							case "SheetVeryHidden": wsprops.Hidden = 2; break; | ||||
| 						} | ||||
| 						else pidx = Rn.index + Rn[0].length; | ||||
| 						break; | ||||
| 					case 'Unsynced': break; | ||||
| 					case 'Visible': break; | ||||
| 					case 'Print': break; | ||||
| 					case 'Panes': break; | ||||
| 					case 'Scale': break; | ||||
| @ -740,6 +750,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 	var out = ({}/*:any*/); | ||||
| 	if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets; | ||||
| 	out.SheetNames = sheetnames; | ||||
| 	out.Workbook = Workbook; | ||||
| 	out.SSF = SSF.get_table(); | ||||
| 	out.Props = Props; | ||||
| 	out.Custprops = Custprops; | ||||
| @ -776,6 +787,22 @@ function write_sty_xlml(wb, opts)/*:string*/ { | ||||
| 	/* Styles */ | ||||
| 	return ""; | ||||
| } | ||||
| /* WorksheetOptions */ | ||||
| function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ { | ||||
| 	var o = []; | ||||
| 	/* PageSetup */ | ||||
| 	if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) { | ||||
| 		/* Visible */ | ||||
| 		if(!!wb.Workbook.Sheets[idx].Hidden) o.push("<Visible>" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "</Visible>"); | ||||
| 		else { | ||||
| 			/* Selected */ | ||||
| 			for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break; | ||||
| 			if(i == idx) o.push("<Selected/>"); | ||||
| 		} | ||||
| 	} | ||||
| 	if(o.length == 0) return ""; | ||||
| 	return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x}); | ||||
| } | ||||
| /* TODO */ | ||||
| function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| 	if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>"; | ||||
| @ -861,7 +888,10 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ { | ||||
| 	/* Table */ | ||||
| 	var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : ""; | ||||
| 	if(t.length > 0) o.push("<Table>" + t + "</Table>"); | ||||
| 
 | ||||
| 	/* WorksheetOptions */ | ||||
| 	o.push(write_ws_xlml_wsopts(ws, opts, idx, wb)); | ||||
| 
 | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_xlml(wb, opts)/*:string*/ { | ||||
|  | ||||
| @ -98,6 +98,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var cell_valid = true; | ||||
| 	var XFs = []; /* XF records */ | ||||
| 	var palette = []; | ||||
| 	var Workbook = { Sheets:[] }, wsprops = {}; | ||||
| 	var get_rgb = function getrgb(icv) { | ||||
| 		if(icv < 8) return XLSIcv[icv]; | ||||
| 		if(icv < 64) return palette[icv-8] || XLSIcv[icv]; | ||||
| @ -269,6 +270,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						if(objects.length > 0) out["!objects"] = objects; | ||||
| 						if(colinfo.length > 0) out["!cols"] = colinfo; | ||||
| 						if(rowinfo.length > 0) out["!rows"] = rowinfo; | ||||
| 						Workbook.Sheets.push(wsprops); | ||||
| 					} | ||||
| 					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out; | ||||
| 					out = {}; | ||||
| @ -285,6 +287,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					if(file_depth++) break; | ||||
| 					cell_valid = true; | ||||
| 					out = {}; | ||||
| 
 | ||||
| 					if(opts.biff < 5) { | ||||
| 						if(cur_sheet === "") cur_sheet = "Sheet1"; | ||||
| 						range = {s:{r:0,c:0},e:{r:0,c:0}}; | ||||
| @ -301,6 +304,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					colinfo = []; rowinfo = []; | ||||
| 					defwidth = defheight = 0; | ||||
| 					seencol = false; | ||||
| 					wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet }; | ||||
| 				} break; | ||||
| 
 | ||||
| 				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': { | ||||
| @ -705,6 +709,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	if(opts.enc) wb.Encryption = opts.enc; | ||||
| 	wb.Metadata = {}; | ||||
| 	if(country !== undefined) wb.Metadata.Country = country; | ||||
| 	wb.Workbook = Workbook; | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -114,14 +114,15 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var i=0; | ||||
| 	var sheetRels = ({}/*:any*/); | ||||
| 	var path, relsPath; | ||||
| 	if(!props.Worksheets) { | ||||
| 
 | ||||
| 	//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'; | ||||
|  | ||||
| @ -33,8 +33,10 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 
 | ||||
| 	/*::if(!wb.Props) throw "unreachable"; */ | ||||
| 	f = "docProps/app.xml"; | ||||
| 	wb.Props.SheetNames = wb.SheetNames; | ||||
| 	wb.Props.Worksheets = wb.SheetNames.length; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	/*:: else if(!wb.Props) throw "unreachable"; */ | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| 	add_rels(opts.rels, 3, f, RELS.EXT_PROPS); | ||||
|  | ||||
							
								
								
									
										31
									
								
								docbits/73_sheetprops.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										31
									
								
								docbits/73_sheetprops.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| #### Sheet Visibility | ||||
| 
 | ||||
| Excel enables hiding sheets in the lower tab bar.  The sheet data is stored in | ||||
| the file but the UI does not readily make it available.  Standard hidden sheets | ||||
| are revealed in the unhide menu.  Excel also has "very hidden" sheets which | ||||
| cannot be revealed in the menu.  It is only accessible in the VB Editor! | ||||
| 
 | ||||
| The visibility setting is stored in the `Hidden` property of the sheet props | ||||
| array.  The values are: | ||||
| 
 | ||||
| | Value | Definition  | | ||||
| |:-----:|:------------| | ||||
| |   0   | Visible     | | ||||
| |   1   | Hidden      | | ||||
| |   2   | Very Hidden | | ||||
| 
 | ||||
| With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>: | ||||
| 
 | ||||
| ```js | ||||
| > wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] }) | ||||
| [ [ 'Visible', 0 ], [ 'Hidden', 1 ], [ 'VeryHidden', 2 ] ] | ||||
| ``` | ||||
| 
 | ||||
| Non-Excel formats do not support the Very Hidden state.  The best way to test | ||||
| if a sheet is visible is to check if the `Hidden` property is logical negation: | ||||
| 
 | ||||
| ```js | ||||
| > wb.Workbook.Sheets.map(function(x) { return [x.name, !x.Hidden] }) | ||||
| [ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ] | ||||
| ``` | ||||
| 
 | ||||
| @ -24,6 +24,7 @@ | ||||
|     + [Formulae](README.md#formulae) | ||||
|     + [Column Properties](README.md#column-properties) | ||||
|     + [Hyperlinks](README.md#hyperlinks) | ||||
|     + [Sheet Visibility](README.md#sheet-visibility) | ||||
| - [Parsing Options](README.md#parsing-options) | ||||
|   * [Input Type](README.md#input-type) | ||||
|   * [Guessing File Type](README.md#guessing-file-type) | ||||
|  | ||||
							
								
								
									
										15
									
								
								misc/flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								misc/flow.js
									
									
									
									
									
								
							| @ -17,10 +17,25 @@ type Workbook = { | ||||
| 	Custprops?: any; | ||||
| 	Themes?: any; | ||||
| 
 | ||||
| 	Workbook?: WBWBProps; | ||||
| 
 | ||||
| 	SSF?: {[n:number]:string}; | ||||
| 	cfb?: any; | ||||
| }; | ||||
| 
 | ||||
| type WorkbookProps = { | ||||
| 	SheetNames?: Array<string>; | ||||
| } | ||||
| 
 | ||||
| type WBWBProps = { | ||||
| 	Sheets: Array<WBWSProp>; | ||||
| }; | ||||
| 
 | ||||
| type WBWSProp = { | ||||
| 	Hidden?: number; | ||||
| 	name?: string; | ||||
| } | ||||
| 
 | ||||
| interface CellAddress { | ||||
| 	r:number; | ||||
| 	c:number; | ||||
|  | ||||
							
								
								
									
										84
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										84
									
								
								test.js
									
									
									
									
									
								
							| @ -73,6 +73,11 @@ var paths = { | ||||
| 	cwxml:  dir + 'column_width.xml', | ||||
| 	cwxlsx:  dir + 'column_width.xlsx', | ||||
| 	cwxlsb:  dir + 'column_width.xlsx', | ||||
| 	svxls:  dir + 'sheet_visibility.xls', | ||||
| 	svxls5: dir + 'sheet_visibility.xls', | ||||
| 	svxml:  dir + 'sheet_visibility.xml', | ||||
| 	svxlsx: dir + 'sheet_visibility.xlsx', | ||||
| 	svxlsb: dir + 'sheet_visibility.xlsb', | ||||
| 	swcxls: dir + 'apachepoi_SimpleWithComments.xls', | ||||
| 	swcxml: dir + '2011/apachepoi_SimpleWithComments.xls.xml', | ||||
| 	swcxlsx: dir + 'apachepoi_SimpleWithComments.xlsx', | ||||
| @ -616,21 +621,54 @@ function hlink(wb) { | ||||
| 
 | ||||
| 
 | ||||
| describe('parse features', function() { | ||||
| 	if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){ | ||||
| 		var X = require(modp); | ||||
| 		var sheet = 'Sheet1'; | ||||
| 		var wb1=X.readFile(paths.swcxlsx); | ||||
| 		var wb2=X.readFile(paths.swcxlsb); | ||||
| 		var wb3=X.readFile(paths.swcxls); | ||||
| 		var wb4=X.readFile(paths.swcxml); | ||||
| 	describe('sheet visibility', function() { | ||||
| 		var wb1, wb2, wb3, wb4, wb5; | ||||
| 		var bef = (function() { | ||||
| 			wb1 = X.readFile(paths.svxls); | ||||
| 			wb2 = X.readFile(paths.svxls5); | ||||
| 			wb3 = X.readFile(paths.svxml); | ||||
| 			wb4 = X.readFile(paths.svxlsx); | ||||
| 			wb5 = X.readFile(paths.svxlsb); | ||||
| 		}); | ||||
| 		if(typeof before != 'undefined') before(bef); | ||||
| 		else it('before', bef); | ||||
| 
 | ||||
| 		[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.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "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"); | ||||
| 		it('should detect visible sheets', function() { | ||||
| 			[wb1, wb2, wb3, wb4, wb5].forEach(function(wb) { | ||||
| 				assert(!wb.Workbook.Sheets[0].Hidden); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should detect all hidden sheets', function() { | ||||
| 			[wb1, wb2, wb3, wb4, wb5].forEach(function(wb) { | ||||
| 				assert(wb.Workbook.Sheets[1].Hidden); | ||||
| 				assert(wb.Workbook.Sheets[2].Hidden); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should distinguish very hidden sheets', function() { | ||||
| 			[wb1, wb2, wb3, wb4, wb5].forEach(function(wb) { | ||||
| 				assert.equal(wb.Workbook.Sheets[1].Hidden,1); | ||||
| 				assert.equal(wb.Workbook.Sheets[2].Hidden,2); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	describe('comments', function() { | ||||
| 		if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){ | ||||
| 			var X = require(modp); | ||||
| 			var sheet = 'Sheet1'; | ||||
| 			var wb1=X.readFile(paths.swcxlsx); | ||||
| 			var wb2=X.readFile(paths.swcxlsb); | ||||
| 			var wb3=X.readFile(paths.swcxls); | ||||
| 			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.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "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"); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| @ -1000,6 +1038,24 @@ describe('roundtrip features', function() { | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 	describe('should preserve sheet visibility', function() { [ | ||||
| 			['xlml', paths.svxml], | ||||
| 			['xlsx', paths.svxlsx], | ||||
| 			['xlsb', paths.svxlsb] | ||||
| 		].forEach(function(w) { | ||||
| 			it(w[0], function() { | ||||
| 				var wb1 = X.readFile(w[1]); | ||||
| 				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"buffer"}), {type:"buffer"}); | ||||
| 				var wbs1 = wb1.Workbook.Sheets; | ||||
| 				var wbs2 = wb2.Workbook.Sheets; | ||||
| 				assert.equal(wbs1.length, wbs2.length); | ||||
| 				for(var i = 0; i < wbs1.length; ++i) { | ||||
| 					assert.equal(wbs1[i].name, wbs2[i].name); | ||||
| 					assert.equal(wbs1[i].Hidden, wbs2[i].Hidden); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| function password_file(x){return x.match(/^password.*\.xls$/); } | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit cbafd3a184d0c668aaae1f9f8420ccaed74ad8e5 | ||||
| Subproject commit 7926b8cd03370487edfa9476cad10b532ef22e99 | ||||
							
								
								
									
										19
									
								
								tests.lst
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										19
									
								
								tests.lst
									
									
									
									
									
								
							| @ -34,6 +34,7 @@ pivot_table_named_range.xlsb | ||||
| pivot_table_test.xlsb | ||||
| rich_text_stress.xlsb | ||||
| row_height.xlsb | ||||
| sheet_visibility.xlsb | ||||
| sized_boxen.xlsb | ||||
| smart_tags_2007.xlsb | ||||
| sushi.xlsb | ||||
| @ -199,7 +200,6 @@ apachepoi_DataTableCities.xlsx | ||||
| apachepoi_DataValidationEvaluations.xlsx | ||||
| apachepoi_DataValidations-49244.xlsx | ||||
| # apachepoi_DateFormatTests.xlsx # xlml | ||||
| apachepoi_DateFormatTests.xlsx.xlsx | ||||
| apachepoi_ElapsedFormatTests.xlsx | ||||
| apachepoi_ExcelTables.xlsx | ||||
| apachepoi_ForShifting.xlsx | ||||
| @ -288,6 +288,7 @@ apachepoi_workbookProtection_worksheet_protected.xlsx | ||||
| apachepoi_xlsx-jdbc.xlsx | ||||
| calendar_stress_test.xlsx.pending | ||||
| cell_style_simple.xlsx | ||||
| column_width.xlsx | ||||
| comments_stress_test.xlsx | ||||
| custom_properties.xlsx | ||||
| defined_names_simple.xlsx | ||||
| @ -407,6 +408,10 @@ roo_time-test.xlsx | ||||
| roo_whitespace.xlsx | ||||
| roo_x000D.xlsx | ||||
| roo_zero-padded-number.xlsx | ||||
| row_height.xlsx | ||||
| sheet_visibility.xlsx | ||||
| sheet_visibility_strict.xlsx | ||||
| sized_boxen.xlsx | ||||
| smart_tags_2007.xlsx | ||||
| spout-xlsx_attack_billion_laughs.xlsx | ||||
| spout-xlsx_attack_quadratic_blowup.xlsx | ||||
| @ -578,6 +583,7 @@ roo_time-test.ods | ||||
| roo_type_excel.ods | ||||
| roo_type_excelx.ods | ||||
| roo_whitespace.ods | ||||
| sheet_visibility.ods | ||||
| spout-ods_attack_billion_laughs.ods | ||||
| spout-ods_attack_quadratic_blowup.ods | ||||
| # spout-ods_file_corrupted.ods | ||||
| @ -1001,6 +1007,7 @@ apachepoi_xor-encryption-abc.xls.pending | ||||
| # apachepoi_yearfracExamples.xls # xlml | ||||
| calendar_stress_test.xls.pending | ||||
| cell_style_simple.xls | ||||
| column_width.xls | ||||
| comments_stress_test.xls | ||||
| custom_properties.xls | ||||
| defined_names_simple.xls | ||||
| @ -1233,6 +1240,10 @@ roo_time-test.xls | ||||
| roo_type_excelx.xls | ||||
| # roo_type_openoffice.xls # incorrect baseline | ||||
| roo_whitespace.xls | ||||
| row_height.xls | ||||
| sheet_visibility.xls | ||||
| sheet_visibility5.xls | ||||
| sized_boxen.xls | ||||
| smart_tags_2007.xls | ||||
| sushi.xls | ||||
| text_and_numbers.xls | ||||
| @ -1261,6 +1272,7 @@ RkNumber.xlsx.xml | ||||
| apachepoi_SampleSS.xml | ||||
| calendar_stress_test.xml.pending | ||||
| cell_style_simple.xml | ||||
| column_width.xml | ||||
| comments_stress_test.xls.xml | ||||
| comments_stress_test.xlsb.xml | ||||
| comments_stress_test.xlsx.xml | ||||
| @ -1327,12 +1339,15 @@ roo_formula_parse_error.xml | ||||
| # roo_numbers1.xml # SSF TODO | ||||
| roo_only_one_sheet.xml | ||||
| roo_paragraph.xml | ||||
| # roo_sheet1.xml | ||||
| # roo_simple_spreadsheet.xml # SSF TODO | ||||
| # roo_simple_spreadsheet_from_italo.xml # SSF TODO | ||||
| roo_style.xml | ||||
| # roo_time-test.xml # SSF TODO | ||||
| # roo_whitespace.xml # SSF TODO | ||||
| # roo_sheet1.xml | ||||
| row_height.xml | ||||
| sheet_visibility.xml | ||||
| sized_boxen.xml | ||||
| smart_tags_2007.xml | ||||
| sushi.xml | ||||
| text_and_numbers.xml | ||||
|  | ||||
| @ -63,6 +63,11 @@ var paths = { | ||||
| 	cwxml:  dir + 'column_width.xml', | ||||
| 	cwxlsx:  dir + 'column_width.xlsx', | ||||
| 	cwxlsb:  dir + 'column_width.xlsx', | ||||
| 	svxls:  dir + 'sheet_visibility.xls', | ||||
| 	svxls5: dir + 'sheet_visibility.xls', | ||||
| 	svxml:  dir + 'sheet_visibility.xml', | ||||
| 	svxlsx: dir + 'sheet_visibility.xlsx', | ||||
| 	svxlsb: dir + 'sheet_visibility.xlsb', | ||||
| 	swcxls: dir + 'apachepoi_SimpleWithComments.xls', | ||||
| 	swcxml: dir + '2011/apachepoi_SimpleWithComments.xls.xml', | ||||
| 	swcxlsx: dir + 'apachepoi_SimpleWithComments.xlsx', | ||||
| @ -458,21 +463,54 @@ function hlink(wb) { | ||||
| 
 | ||||
| 
 | ||||
| describe('parse features', function() { | ||||
| 	if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){ | ||||
| 		var X = require(modp); | ||||
| 		var sheet = 'Sheet1'; | ||||
| 		var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:"binary"}); | ||||
| 		var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:"binary"}); | ||||
| 		var wb3=X.read(fs.readFileSync(paths.swcxls), {type:"binary"}); | ||||
| 		var wb4=X.read(fs.readFileSync(paths.swcxml), {type:"binary"}); | ||||
| 	describe('sheet visibility', function() { | ||||
| 		var wb1, wb2, wb3, wb4, wb5; | ||||
| 		var bef = (function() { | ||||
| 			wb1 = X.read(fs.readFileSync(paths.svxls), {type:"binary"}); | ||||
| 			wb2 = X.read(fs.readFileSync(paths.svxls5), {type:"binary"}); | ||||
| 			wb3 = X.read(fs.readFileSync(paths.svxml), {type:"binary"}); | ||||
| 			wb4 = X.read(fs.readFileSync(paths.svxlsx), {type:"binary"}); | ||||
| 			wb5 = X.read(fs.readFileSync(paths.svxlsb), {type:"binary"}); | ||||
| 		}); | ||||
| 		if(typeof before != 'undefined') before(bef); | ||||
| 		else it('before', bef); | ||||
| 
 | ||||
| 		[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.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "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"); | ||||
| 		it('should detect visible sheets', function() { | ||||
| 			[/*wb1, wb2, wb3, wb4,*/ wb5].forEach(function(wb) { | ||||
| 				assert(!wb.Workbook.Sheets[0].Hidden); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should detect all hidden sheets', function() { | ||||
| 			[/*wb1, wb2, wb3, wb4,*/ wb5].forEach(function(wb) { | ||||
| 				assert(wb.Workbook.Sheets[1].Hidden); | ||||
| 				assert(wb.Workbook.Sheets[2].Hidden); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should distinguish very hidden sheets', function() { | ||||
| 			[/*wb1, wb2, wb3, wb4,*/ wb5].forEach(function(wb) { | ||||
| 				assert.equal(wb.Workbook.Sheets[1].Hidden,1); | ||||
| 				assert.equal(wb.Workbook.Sheets[2].Hidden,2); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	describe('comments', function() { | ||||
| 		if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){ | ||||
| 			var X = require(modp); | ||||
| 			var sheet = 'Sheet1'; | ||||
| 			var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:"binary"}); | ||||
| 			var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:"binary"}); | ||||
| 			var wb3=X.read(fs.readFileSync(paths.swcxls), {type:"binary"}); | ||||
| 			var wb4=X.read(fs.readFileSync(paths.swcxml), {type:"binary"}); | ||||
| 
 | ||||
| 			[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.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "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"); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| @ -841,6 +879,24 @@ describe('roundtrip features', function() { | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 	describe('should preserve sheet visibility', function() { [ | ||||
| 			['xlml', paths.svxml], | ||||
| 			['xlsx', paths.svxlsx], | ||||
| 			['xlsb', paths.svxlsb] | ||||
| 		].forEach(function(w) { | ||||
| 			it(w[0], function() { | ||||
| 				var wb1 = X.read(fs.readFileSync(w[1]), {type:"binary"}); | ||||
| 				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"binary"}), {type:"binary"}); | ||||
| 				var wbs1 = wb1.Workbook.Sheets; | ||||
| 				var wbs2 = wb2.Workbook.Sheets; | ||||
| 				assert.equal(wbs1.length, wbs2.length); | ||||
| 				for(var i = 0; i < wbs1.length; ++i) { | ||||
| 					assert.equal(wbs1[i].name, wbs2[i].name); | ||||
| 					assert.equal(wbs1[i].Hidden, wbs2[i].Hidden); | ||||
| 				} | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| function password_file(x){return x.match(/^password.*\.xls$/); } | ||||
|  | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -39,6 +39,11 @@ | ||||
| ./test_files/column_width.xml | ||||
| ./test_files/column_width.xlsx | ||||
| ./test_files/column_width.xlsx | ||||
| ./test_files/sheet_visibility.xls | ||||
| ./test_files/sheet_visibility.xls | ||||
| ./test_files/sheet_visibility.xml | ||||
| ./test_files/sheet_visibility.xlsx | ||||
| ./test_files/sheet_visibility.xlsb | ||||
| ./test_files/apachepoi_SimpleWithComments.xls | ||||
| ./test_files/2011/apachepoi_SimpleWithComments.xls.xml | ||||
| ./test_files/apachepoi_SimpleWithComments.xlsx | ||||
|  | ||||
| @ -80,6 +80,13 @@ console.log("JSON Data: "); console.log(XLSX.utils.sheet_to_json(ws, {header:1}) | ||||
| console.log("Worksheet Model:") | ||||
| console.log(ws); | ||||
| 
 | ||||
| /* TEST: hidden sheets */ | ||||
| 
 | ||||
| wb.SheetNames.push("Hidden"); | ||||
| wb.Sheets["Hidden"] = XLSX.utils.aoa_to_sheet(["Hidden".split(""), [1,2,3]]); | ||||
| wb.Workbook = {Sheets:[]}; | ||||
| wb.Workbook.Sheets[1] = {Hidden:1}; | ||||
| 
 | ||||
| /* write file */ | ||||
| XLSX.writeFile(wb, 'sheetjs.xlsx', {bookSST:true}); | ||||
| XLSX.writeFile(wb, 'sheetjs.xlsm'); | ||||
|  | ||||
							
								
								
									
										115
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										115
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -1915,6 +1915,7 @@ function prep_blob(blob, pos/*:number*/) { | ||||
| } | ||||
| 
 | ||||
| function parsenoop(blob, length/*:number*/) { blob.l += length; } | ||||
| function parsenooplog(blob, length/*:number*/) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; } | ||||
| 
 | ||||
| function writenoop(blob, length/*:number*/) { blob.l += length; } | ||||
| 
 | ||||
| @ -3070,8 +3071,8 @@ function parse_ext_props(data, p) { | ||||
| 		var v = parseVector(q.HeadingPairs); | ||||
| 		var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; }); | ||||
| 		var idx = 0, len = 0; | ||||
| 		for(var i = 0; i !== v.length; ++i) { | ||||
| 			len = +(v[++i].v); | ||||
| 		for(var i = 0; i !== v.length; i+=2) { | ||||
| 			len = +(v[i+1].v); | ||||
| 			switch(v[i].v) { | ||||
| 				case "Worksheets": | ||||
| 				case "工作表": | ||||
| @ -3104,6 +3105,7 @@ function parse_ext_props(data, p) { | ||||
| 			idx += len; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| @ -9208,7 +9210,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook | ||||
| 			if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell); | ||||
| 		} | ||||
| 		if(r.length > 0) { | ||||
| 			var params = {r:rr} | ||||
| 			var params = ({r:rr}/*:any*/); | ||||
| 			if(rows && rows[R]) { | ||||
| 				var row = rows[R]; | ||||
| 				if(row.hidden) params.hidden = 1; | ||||
| @ -10086,7 +10088,7 @@ var WBViewDef = [ | ||||
| 
 | ||||
| /* 18.2.19 (CT_Sheet) Defaults */ | ||||
| var SheetDef = [ | ||||
| 	['state', 'visible'] | ||||
| 	//['state', 'visible']
 | ||||
| ]; | ||||
| 
 | ||||
| /* 18.2.2  (CT_CalcPr) Defaults */ | ||||
| @ -10199,7 +10201,15 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 			/* 18.2.20 sheets CT_Sheets 1 */ | ||||
| 			case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			/* 18.2.19   sheet CT_Sheet + */ | ||||
| 			case '<sheet': delete y[0]; y.name = unescapexml(utf8read(y.name)); wb.Sheets.push(y); break; | ||||
| 			case '<sheet': | ||||
| 				switch(y.state) { | ||||
| 					case "hidden": y.Hidden = 1; break; | ||||
| 					case "veryHidden": y.Hidden = 2; break; | ||||
| 					default: y.Hidden = 0; | ||||
| 				} | ||||
| 				delete y.state; | ||||
| 				y.name = unescapexml(utf8read(y.name)); | ||||
| 				delete y[0]; wb.Sheets.push(y); break; | ||||
| 			case '</sheet>': break; | ||||
| 
 | ||||
| 			/* 18.2.15 functionGroups CT_FunctionGroups ? */ | ||||
| @ -10309,8 +10319,17 @@ function write_wb_xml(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:string*/ { | ||||
| 	o[o.length] = WB_XML_ROOT; | ||||
| 	o[o.length] = (writextag('workbookPr', null, {date1904:safe1904(wb), codeName:"ThisWorkbook"})); | ||||
| 	o[o.length] = "<sheets>"; | ||||
| 	for(var i = 0; i != wb.SheetNames.length; ++i) | ||||
| 		o[o.length] = (writextag('sheet',null,{name:escapexml(wb.SheetNames[i].substr(0,31)), sheetId:""+(i+1), "r:id":"rId"+(i+1)})); | ||||
| 	var sheets = wb.Workbook && wb.Workbook.Sheets || []; | ||||
| 	for(var i = 0; i != wb.SheetNames.length; ++i) { | ||||
| 		var sht = ({name:escapexml(wb.SheetNames[i].substr(0,31))}/*:any*/); | ||||
| 		sht.sheetId = ""+(i+1); | ||||
| 		sht["r:id"] = "rId"+(i+1); | ||||
| 		if(sheets[i]) switch(sheets[i].Hidden) { | ||||
| 			case 1: sht.state = "hidden"; break; | ||||
| 			case 2: sht.state = "veryHidden"; break; | ||||
| 		} | ||||
| 		o[o.length] = (writextag('sheet',null,sht)); | ||||
| 	} | ||||
| 	o[o.length] = "</sheets>"; | ||||
| 	if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| @ -10318,7 +10337,7 @@ function write_wb_xml(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:string*/ { | ||||
| /* [MS-XLSB] 2.4.301 BrtBundleSh */ | ||||
| function parse_BrtBundleSh(data, length/*:number*/) { | ||||
| 	var z = {}; | ||||
| 	z.hsState = data.read_shift(4); //ST_SheetState
 | ||||
| 	z.Hidden = data.read_shift(4); //hsState ST_SheetState
 | ||||
| 	z.iTabID = data.read_shift(4); | ||||
| 	z.strRelID = parse_RelID(data,length-8); | ||||
| 	z.name = parse_XLWideString(data); | ||||
| @ -10326,7 +10345,7 @@ function parse_BrtBundleSh(data, length/*:number*/) { | ||||
| } | ||||
| function write_BrtBundleSh(data, o) { | ||||
| 	if(!o) o = new_buf(127); | ||||
| 	o.write_shift(4, data.hsState); | ||||
| 	o.write_shift(4, data.Hidden); | ||||
| 	o.write_shift(4, data.iTabID); | ||||
| 	write_RelID(data.strRelID, o); | ||||
| 	write_XLWideString(data.name.substr(0,31), o); | ||||
| @ -10455,7 +10474,8 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ { | ||||
| function write_BUNDLESHS(ba, wb, opts) { | ||||
| 	write_record(ba, "BrtBeginBundleShs"); | ||||
| 	for(var idx = 0; idx != wb.SheetNames.length; ++idx) { | ||||
| 		var d = { hsState: 0, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0; | ||||
| 		var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		write_record(ba, "BrtBundleSh", write_BrtBundleSh(d)); | ||||
| 	} | ||||
| 	write_record(ba, "BrtEndBundleShs"); | ||||
| @ -10473,9 +10493,34 @@ function write_BrtFileVersion(data, o) { | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.298 BrtBookView */ | ||||
| function write_BrtBookView(idx, o) { | ||||
| 	if(!o) o = new_buf(29); | ||||
| 	o.write_shift(-4, 0); | ||||
| 	o.write_shift(-4, 460); | ||||
| 	o.write_shift(4,  28800); | ||||
| 	o.write_shift(4,  17600); | ||||
| 	o.write_shift(4,  500); | ||||
| 	o.write_shift(4,  idx); | ||||
| 	o.write_shift(4,  idx); | ||||
| 	var flags = 0x78; | ||||
| 	o.write_shift(1,  flags); | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.60 Workbook */ | ||||
| function write_BOOKVIEWS(ba, wb, opts) { | ||||
| 	/* required if hidden tab appears before visible tab */ | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) return; | ||||
| 	var sheets = wb.Workbook.Sheets; | ||||
| 	var i = 0, vistab = -1, hidden = -1; | ||||
| 	for(; i < sheets.length; ++i) { | ||||
| 		if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i; | ||||
| 		else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i; | ||||
| 	} | ||||
| 	if(hidden > vistab) return; | ||||
| 	write_record(ba, "BrtBeginBookViews"); | ||||
| 	write_record(ba, "BrtBookView", write_BrtBookView(vistab)); | ||||
| 	/* 1*(BrtBookView *FRT) */ | ||||
| 	write_record(ba, "BrtEndBookViews"); | ||||
| } | ||||
| @ -10509,7 +10554,7 @@ function write_wb_bin(wb, opts) { | ||||
| 	write_record(ba, "BrtWbProp", write_BrtWbProp()); | ||||
| 	/* [ACABSPATH] */ | ||||
| 	/* [[BrtBookProtectionIso] BrtBookProtection] */ | ||||
| 	/* write_BOOKVIEWS(ba, wb, opts); */ | ||||
| 	write_BOOKVIEWS(ba, wb, opts); | ||||
| 	write_BUNDLESHS(ba, wb, opts); | ||||
| 	/* [FNGROUP] */ | ||||
| 	/* [EXTERNALS] */ | ||||
| @ -10790,6 +10835,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 	var cstys = [], csty, seencol = false; | ||||
| 	var arrayf = []; | ||||
| 	var rowinfo = []; | ||||
| 	var Workbook = { Sheets:[] }, wsprops = {}; | ||||
| 	xlmlregex.lastIndex = 0; | ||||
| 	str = str.replace(/<!--([^\u2603]*?)-->/mg,""); | ||||
| 	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| @ -10864,6 +10910,8 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 				mergecells = []; | ||||
| 				arrayf = []; | ||||
| 				rowinfo = []; | ||||
| 				wsprops = {name:sheetname, Hidden:0}; | ||||
| 				Workbook.Sheets.push(wsprops); | ||||
| 			} | ||||
| 			break; | ||||
| 		case 'Table': | ||||
| @ -11088,8 +11136,15 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 
 | ||||
| 				/* WorksheetOptions */ | ||||
| 				case 'WorksheetOptions': switch(Rn[3]) { | ||||
| 					case 'Visible': | ||||
| 						if(Rn[0].slice(-2) === "/>"){} | ||||
| 						else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) { | ||||
| 							case "SheetHidden": wsprops.Hidden = 1; break; | ||||
| 							case "SheetVeryHidden": wsprops.Hidden = 2; break; | ||||
| 						} | ||||
| 						else pidx = Rn.index + Rn[0].length; | ||||
| 						break; | ||||
| 					case 'Unsynced': break; | ||||
| 					case 'Visible': break; | ||||
| 					case 'Print': break; | ||||
| 					case 'Panes': break; | ||||
| 					case 'Scale': break; | ||||
| @ -11344,6 +11399,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ { | ||||
| 	var out = ({}/*:any*/); | ||||
| 	if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets; | ||||
| 	out.SheetNames = sheetnames; | ||||
| 	out.Workbook = Workbook; | ||||
| 	out.SSF = SSF.get_table(); | ||||
| 	out.Props = Props; | ||||
| 	out.Custprops = Custprops; | ||||
| @ -11380,6 +11436,22 @@ function write_sty_xlml(wb, opts)/*:string*/ { | ||||
| 	/* Styles */ | ||||
| 	return ""; | ||||
| } | ||||
| /* WorksheetOptions */ | ||||
| function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ { | ||||
| 	var o = []; | ||||
| 	/* PageSetup */ | ||||
| 	if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) { | ||||
| 		/* Visible */ | ||||
| 		if(!!wb.Workbook.Sheets[idx].Hidden) o.push("<Visible>" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "</Visible>"); | ||||
| 		else { | ||||
| 			/* Selected */ | ||||
| 			for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break; | ||||
| 			if(i == idx) o.push("<Selected/>"); | ||||
| 		} | ||||
| 	} | ||||
| 	if(o.length == 0) return ""; | ||||
| 	return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x}); | ||||
| } | ||||
| /* TODO */ | ||||
| function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| 	if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>"; | ||||
| @ -11465,7 +11537,10 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ { | ||||
| 	/* Table */ | ||||
| 	var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : ""; | ||||
| 	if(t.length > 0) o.push("<Table>" + t + "</Table>"); | ||||
| 
 | ||||
| 	/* WorksheetOptions */ | ||||
| 	o.push(write_ws_xlml_wsopts(ws, opts, idx, wb)); | ||||
| 
 | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_xlml(wb, opts)/*:string*/ { | ||||
| @ -11584,6 +11659,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var cell_valid = true; | ||||
| 	var XFs = []; /* XF records */ | ||||
| 	var palette = []; | ||||
| 	var Workbook = { Sheets:[] }, wsprops = {}; | ||||
| 	var get_rgb = function getrgb(icv) { | ||||
| 		if(icv < 8) return XLSIcv[icv]; | ||||
| 		if(icv < 64) return palette[icv-8] || XLSIcv[icv]; | ||||
| @ -11755,6 +11831,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						if(objects.length > 0) out["!objects"] = objects; | ||||
| 						if(colinfo.length > 0) out["!cols"] = colinfo; | ||||
| 						if(rowinfo.length > 0) out["!rows"] = rowinfo; | ||||
| 						Workbook.Sheets.push(wsprops); | ||||
| 					} | ||||
| 					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out; | ||||
| 					out = {}; | ||||
| @ -11771,6 +11848,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					if(file_depth++) break; | ||||
| 					cell_valid = true; | ||||
| 					out = {}; | ||||
| 
 | ||||
| 					if(opts.biff < 5) { | ||||
| 						if(cur_sheet === "") cur_sheet = "Sheet1"; | ||||
| 						range = {s:{r:0,c:0},e:{r:0,c:0}}; | ||||
| @ -11787,6 +11865,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					colinfo = []; rowinfo = []; | ||||
| 					defwidth = defheight = 0; | ||||
| 					seencol = false; | ||||
| 					wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet }; | ||||
| 				} break; | ||||
| 
 | ||||
| 				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': { | ||||
| @ -12191,6 +12270,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	if(opts.enc) wb.Encryption = opts.enc; | ||||
| 	wb.Metadata = {}; | ||||
| 	if(country !== undefined) wb.Metadata.Country = country; | ||||
| 	wb.Workbook = Workbook; | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
| @ -14340,14 +14420,15 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var i=0; | ||||
| 	var sheetRels = ({}/*:any*/); | ||||
| 	var path, relsPath; | ||||
| 	if(!props.Worksheets) { | ||||
| 
 | ||||
| 	//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'; | ||||
| @ -14428,8 +14509,10 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 
 | ||||
| 	/*::if(!wb.Props) throw "unreachable"; */ | ||||
| 	f = "docProps/app.xml"; | ||||
| 	wb.Props.SheetNames = wb.SheetNames; | ||||
| 	wb.Props.Worksheets = wb.SheetNames.length; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| 	add_rels(opts.rels, 3, f, RELS.EXT_PROPS); | ||||
|  | ||||
							
								
								
									
										115
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										115
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -1864,6 +1864,7 @@ function prep_blob(blob, pos) { | ||||
| } | ||||
| 
 | ||||
| function parsenoop(blob, length) { blob.l += length; } | ||||
| function parsenooplog(blob, length) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; } | ||||
| 
 | ||||
| function writenoop(blob, length) { blob.l += length; } | ||||
| 
 | ||||
| @ -3018,8 +3019,8 @@ function parse_ext_props(data, p) { | ||||
| 		var v = parseVector(q.HeadingPairs); | ||||
| 		var parts = parseVector(q.TitlesOfParts).map(function(x) { return x.v; }); | ||||
| 		var idx = 0, len = 0; | ||||
| 		for(var i = 0; i !== v.length; ++i) { | ||||
| 			len = +(v[++i].v); | ||||
| 		for(var i = 0; i !== v.length; i+=2) { | ||||
| 			len = +(v[i+1].v); | ||||
| 			switch(v[i].v) { | ||||
| 				case "Worksheets": | ||||
| 				case "工作表": | ||||
| @ -3052,6 +3053,7 @@ function parse_ext_props(data, p) { | ||||
| 			idx += len; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| @ -9153,7 +9155,7 @@ function write_ws_xml_data(ws, opts, idx, wb, rels) { | ||||
| 			if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell); | ||||
| 		} | ||||
| 		if(r.length > 0) { | ||||
| 			var params = {r:rr} | ||||
| 			var params = ({r:rr}); | ||||
| 			if(rows && rows[R]) { | ||||
| 				var row = rows[R]; | ||||
| 				if(row.hidden) params.hidden = 1; | ||||
| @ -10031,7 +10033,7 @@ var WBViewDef = [ | ||||
| 
 | ||||
| /* 18.2.19 (CT_Sheet) Defaults */ | ||||
| var SheetDef = [ | ||||
| 	['state', 'visible'] | ||||
| 	//['state', 'visible']
 | ||||
| ]; | ||||
| 
 | ||||
| /* 18.2.2  (CT_CalcPr) Defaults */ | ||||
| @ -10144,7 +10146,15 @@ function parse_wb_xml(data, opts) { | ||||
| 			/* 18.2.20 sheets CT_Sheets 1 */ | ||||
| 			case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			/* 18.2.19   sheet CT_Sheet + */ | ||||
| 			case '<sheet': delete y[0]; y.name = unescapexml(utf8read(y.name)); wb.Sheets.push(y); break; | ||||
| 			case '<sheet': | ||||
| 				switch(y.state) { | ||||
| 					case "hidden": y.Hidden = 1; break; | ||||
| 					case "veryHidden": y.Hidden = 2; break; | ||||
| 					default: y.Hidden = 0; | ||||
| 				} | ||||
| 				delete y.state; | ||||
| 				y.name = unescapexml(utf8read(y.name)); | ||||
| 				delete y[0]; wb.Sheets.push(y); break; | ||||
| 			case '</sheet>': break; | ||||
| 
 | ||||
| 			/* 18.2.15 functionGroups CT_FunctionGroups ? */ | ||||
| @ -10254,8 +10264,17 @@ function write_wb_xml(wb, opts) { | ||||
| 	o[o.length] = WB_XML_ROOT; | ||||
| 	o[o.length] = (writextag('workbookPr', null, {date1904:safe1904(wb), codeName:"ThisWorkbook"})); | ||||
| 	o[o.length] = "<sheets>"; | ||||
| 	for(var i = 0; i != wb.SheetNames.length; ++i) | ||||
| 		o[o.length] = (writextag('sheet',null,{name:escapexml(wb.SheetNames[i].substr(0,31)), sheetId:""+(i+1), "r:id":"rId"+(i+1)})); | ||||
| 	var sheets = wb.Workbook && wb.Workbook.Sheets || []; | ||||
| 	for(var i = 0; i != wb.SheetNames.length; ++i) { | ||||
| 		var sht = ({name:escapexml(wb.SheetNames[i].substr(0,31))}); | ||||
| 		sht.sheetId = ""+(i+1); | ||||
| 		sht["r:id"] = "rId"+(i+1); | ||||
| 		if(sheets[i]) switch(sheets[i].Hidden) { | ||||
| 			case 1: sht.state = "hidden"; break; | ||||
| 			case 2: sht.state = "veryHidden"; break; | ||||
| 		} | ||||
| 		o[o.length] = (writextag('sheet',null,sht)); | ||||
| 	} | ||||
| 	o[o.length] = "</sheets>"; | ||||
| 	if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); } | ||||
| 	return o.join(""); | ||||
| @ -10263,7 +10282,7 @@ function write_wb_xml(wb, opts) { | ||||
| /* [MS-XLSB] 2.4.301 BrtBundleSh */ | ||||
| function parse_BrtBundleSh(data, length) { | ||||
| 	var z = {}; | ||||
| 	z.hsState = data.read_shift(4); //ST_SheetState
 | ||||
| 	z.Hidden = data.read_shift(4); //hsState ST_SheetState
 | ||||
| 	z.iTabID = data.read_shift(4); | ||||
| 	z.strRelID = parse_RelID(data,length-8); | ||||
| 	z.name = parse_XLWideString(data); | ||||
| @ -10271,7 +10290,7 @@ function parse_BrtBundleSh(data, length) { | ||||
| } | ||||
| function write_BrtBundleSh(data, o) { | ||||
| 	if(!o) o = new_buf(127); | ||||
| 	o.write_shift(4, data.hsState); | ||||
| 	o.write_shift(4, data.Hidden); | ||||
| 	o.write_shift(4, data.iTabID); | ||||
| 	write_RelID(data.strRelID, o); | ||||
| 	write_XLWideString(data.name.substr(0,31), o); | ||||
| @ -10400,7 +10419,8 @@ function parse_wb_bin(data, opts) { | ||||
| function write_BUNDLESHS(ba, wb, opts) { | ||||
| 	write_record(ba, "BrtBeginBundleShs"); | ||||
| 	for(var idx = 0; idx != wb.SheetNames.length; ++idx) { | ||||
| 		var d = { hsState: 0, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0; | ||||
| 		var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] }; | ||||
| 		write_record(ba, "BrtBundleSh", write_BrtBundleSh(d)); | ||||
| 	} | ||||
| 	write_record(ba, "BrtEndBundleShs"); | ||||
| @ -10418,9 +10438,34 @@ function write_BrtFileVersion(data, o) { | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.298 BrtBookView */ | ||||
| function write_BrtBookView(idx, o) { | ||||
| 	if(!o) o = new_buf(29); | ||||
| 	o.write_shift(-4, 0); | ||||
| 	o.write_shift(-4, 460); | ||||
| 	o.write_shift(4,  28800); | ||||
| 	o.write_shift(4,  17600); | ||||
| 	o.write_shift(4,  500); | ||||
| 	o.write_shift(4,  idx); | ||||
| 	o.write_shift(4,  idx); | ||||
| 	var flags = 0x78; | ||||
| 	o.write_shift(1,  flags); | ||||
| 	return o.length > o.l ? o.slice(0, o.l) : o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.60 Workbook */ | ||||
| function write_BOOKVIEWS(ba, wb, opts) { | ||||
| 	/* required if hidden tab appears before visible tab */ | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) return; | ||||
| 	var sheets = wb.Workbook.Sheets; | ||||
| 	var i = 0, vistab = -1, hidden = -1; | ||||
| 	for(; i < sheets.length; ++i) { | ||||
| 		if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i; | ||||
| 		else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i; | ||||
| 	} | ||||
| 	if(hidden > vistab) return; | ||||
| 	write_record(ba, "BrtBeginBookViews"); | ||||
| 	write_record(ba, "BrtBookView", write_BrtBookView(vistab)); | ||||
| 	/* 1*(BrtBookView *FRT) */ | ||||
| 	write_record(ba, "BrtEndBookViews"); | ||||
| } | ||||
| @ -10454,7 +10499,7 @@ function write_wb_bin(wb, opts) { | ||||
| 	write_record(ba, "BrtWbProp", write_BrtWbProp()); | ||||
| 	/* [ACABSPATH] */ | ||||
| 	/* [[BrtBookProtectionIso] BrtBookProtection] */ | ||||
| 	/* write_BOOKVIEWS(ba, wb, opts); */ | ||||
| 	write_BOOKVIEWS(ba, wb, opts); | ||||
| 	write_BUNDLESHS(ba, wb, opts); | ||||
| 	/* [FNGROUP] */ | ||||
| 	/* [EXTERNALS] */ | ||||
| @ -10733,6 +10778,7 @@ function parse_xlml_xml(d, opts) { | ||||
| 	var cstys = [], csty, seencol = false; | ||||
| 	var arrayf = []; | ||||
| 	var rowinfo = []; | ||||
| 	var Workbook = { Sheets:[] }, wsprops = {}; | ||||
| 	xlmlregex.lastIndex = 0; | ||||
| 	str = str.replace(/<!--([^\u2603]*?)-->/mg,""); | ||||
| 	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| @ -10806,6 +10852,8 @@ for(var cma = c; cma <= cc; ++cma) { | ||||
| 				mergecells = []; | ||||
| 				arrayf = []; | ||||
| 				rowinfo = []; | ||||
| 				wsprops = {name:sheetname, Hidden:0}; | ||||
| 				Workbook.Sheets.push(wsprops); | ||||
| 			} | ||||
| 			break; | ||||
| 		case 'Table': | ||||
| @ -11030,8 +11078,15 @@ for(var cma = c; cma <= cc; ++cma) { | ||||
| 
 | ||||
| 				/* WorksheetOptions */ | ||||
| 				case 'WorksheetOptions': switch(Rn[3]) { | ||||
| 					case 'Visible': | ||||
| 						if(Rn[0].slice(-2) === "/>"){} | ||||
| 						else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) { | ||||
| 							case "SheetHidden": wsprops.Hidden = 1; break; | ||||
| 							case "SheetVeryHidden": wsprops.Hidden = 2; break; | ||||
| 						} | ||||
| 						else pidx = Rn.index + Rn[0].length; | ||||
| 						break; | ||||
| 					case 'Unsynced': break; | ||||
| 					case 'Visible': break; | ||||
| 					case 'Print': break; | ||||
| 					case 'Panes': break; | ||||
| 					case 'Scale': break; | ||||
| @ -11286,6 +11341,7 @@ for(var cma = c; cma <= cc; ++cma) { | ||||
| 	var out = ({}); | ||||
| 	if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets; | ||||
| 	out.SheetNames = sheetnames; | ||||
| 	out.Workbook = Workbook; | ||||
| 	out.SSF = SSF.get_table(); | ||||
| 	out.Props = Props; | ||||
| 	out.Custprops = Custprops; | ||||
| @ -11321,6 +11377,22 @@ function write_sty_xlml(wb, opts) { | ||||
| 	/* Styles */ | ||||
| 	return ""; | ||||
| } | ||||
| /* WorksheetOptions */ | ||||
| function write_ws_xlml_wsopts(ws, opts, idx, wb) { | ||||
| 	var o = []; | ||||
| 	/* PageSetup */ | ||||
| 	if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) { | ||||
| 		/* Visible */ | ||||
| 		if(!!wb.Workbook.Sheets[idx].Hidden) o.push("<Visible>" + (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden") + "</Visible>"); | ||||
| 		else { | ||||
| 			/* Selected */ | ||||
| 			for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break; | ||||
| 			if(i == idx) o.push("<Selected/>"); | ||||
| 		} | ||||
| 	} | ||||
| 	if(o.length == 0) return ""; | ||||
| 	return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x}); | ||||
| } | ||||
| /* TODO */ | ||||
| function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){ | ||||
| 	if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>"; | ||||
| @ -11406,7 +11478,10 @@ function write_ws_xlml(idx, opts, wb) { | ||||
| 	/* Table */ | ||||
| 	var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : ""; | ||||
| 	if(t.length > 0) o.push("<Table>" + t + "</Table>"); | ||||
| 
 | ||||
| 	/* WorksheetOptions */ | ||||
| 	o.push(write_ws_xlml_wsopts(ws, opts, idx, wb)); | ||||
| 
 | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_xlml(wb, opts) { | ||||
| @ -11525,6 +11600,7 @@ function parse_workbook(blob, options) { | ||||
| 	var cell_valid = true; | ||||
| 	var XFs = []; /* XF records */ | ||||
| 	var palette = []; | ||||
| 	var Workbook = { Sheets:[] }, wsprops = {}; | ||||
| 	var get_rgb = function getrgb(icv) { | ||||
| 		if(icv < 8) return XLSIcv[icv]; | ||||
| 		if(icv < 64) return palette[icv-8] || XLSIcv[icv]; | ||||
| @ -11696,6 +11772,7 @@ function parse_workbook(blob, options) { | ||||
| 						if(objects.length > 0) out["!objects"] = objects; | ||||
| 						if(colinfo.length > 0) out["!cols"] = colinfo; | ||||
| 						if(rowinfo.length > 0) out["!rows"] = rowinfo; | ||||
| 						Workbook.Sheets.push(wsprops); | ||||
| 					} | ||||
| 					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out; | ||||
| 					out = {}; | ||||
| @ -11712,6 +11789,7 @@ function parse_workbook(blob, options) { | ||||
| 					if(file_depth++) break; | ||||
| 					cell_valid = true; | ||||
| 					out = {}; | ||||
| 
 | ||||
| 					if(opts.biff < 5) { | ||||
| 						if(cur_sheet === "") cur_sheet = "Sheet1"; | ||||
| 						range = {s:{r:0,c:0},e:{r:0,c:0}}; | ||||
| @ -11728,6 +11806,7 @@ function parse_workbook(blob, options) { | ||||
| 					colinfo = []; rowinfo = []; | ||||
| 					defwidth = defheight = 0; | ||||
| 					seencol = false; | ||||
| 					wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet }; | ||||
| 				} break; | ||||
| 
 | ||||
| 				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': { | ||||
| @ -12132,6 +12211,7 @@ function parse_workbook(blob, options) { | ||||
| 	if(opts.enc) wb.Encryption = opts.enc; | ||||
| 	wb.Metadata = {}; | ||||
| 	if(country !== undefined) wb.Metadata.Country = country; | ||||
| 	wb.Workbook = Workbook; | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
| @ -14280,14 +14360,15 @@ function parse_zip(zip, opts) { | ||||
| 	var i=0; | ||||
| 	var sheetRels = ({}); | ||||
| 	var path, relsPath; | ||||
| 	if(!props.Worksheets) { | ||||
| 
 | ||||
| 	//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'; | ||||
| @ -14366,8 +14447,10 @@ var zip = new jszip(); | ||||
| 	add_rels(opts.rels, 2, f, RELS.CORE_PROPS); | ||||
| 
 | ||||
| f = "docProps/app.xml"; | ||||
| 	wb.Props.SheetNames = wb.SheetNames; | ||||
| 	wb.Props.Worksheets = wb.SheetNames.length; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| 	add_rels(opts.rels, 3, f, RELS.EXT_PROPS); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user