forked from sheetjs/sheetjs
		
	
							parent
							
								
									7888070603
								
							
						
					
					
						commit
						f90fbd32e5
					
				| @ -1,5 +1,68 @@ | ||||
| /* 18.8.5 borders CT_Borders */ | ||||
| function parse_borders(t, styles, themes, opts) { | ||||
| 	styles.Borders = []; | ||||
| 	var border = {}, sub_border = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch (y[0]) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| 
 | ||||
| 			/* 18.8.4 border CT_Border */ | ||||
| 			case '<border': case '<border>': | ||||
| 				border = {}; | ||||
| 				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; } | ||||
| 				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; } | ||||
| 				styles.Borders.push(border); | ||||
| 				break; | ||||
| 			case '</border>': break; | ||||
| 
 | ||||
| 			/* note: not in spec, appears to be CT_BorderPr */ | ||||
| 			case '<left': case '<left/>': break; | ||||
| 			case '</left>': break; | ||||
| 
 | ||||
| 			/* note: not in spec, appears to be CT_BorderPr */ | ||||
| 			case '<right': case '<right/>': break; | ||||
| 			case '</right>': break; | ||||
| 
 | ||||
| 			/* 18.8.43 top CT_BorderPr */ | ||||
| 			case '<top': case '<top/>': break; | ||||
| 			case '</top>': break; | ||||
| 
 | ||||
| 			/* 18.8.6 bottom CT_BorderPr */ | ||||
| 			case '<bottom': case '<bottom/>': break; | ||||
| 			case '</bottom>': break; | ||||
| 
 | ||||
| 			/* 18.8.13 diagonal CT_BorderPr */ | ||||
| 			case '<diagonal': case '<diagonal/>': break; | ||||
| 			case '</diagonal>': break; | ||||
| 
 | ||||
| 			/* 18.8.25 horizontal CT_BorderPr */ | ||||
| 			case '<horizontal': case '<horizontal/>': break; | ||||
| 			case '</horizontal>': break; | ||||
| 
 | ||||
| 			/* 18.8.44 vertical CT_BorderPr */ | ||||
| 			case '<vertical': case '<vertical/>': break; | ||||
| 			case '</vertical>': break; | ||||
| 
 | ||||
| 			/* 18.8.37 start CT_BorderPr */ | ||||
| 			case '<start': case '<start/>': break; | ||||
| 			case '</start>': break; | ||||
| 
 | ||||
| 			/* 18.8.16 end CT_BorderPr */ | ||||
| 			case '<end': case '<end/>': break; | ||||
| 			case '</end>': break; | ||||
| 
 | ||||
| 			/* 18.8.? color CT_Color */ | ||||
| 			case '<color': case '<color/>': break; | ||||
| 			case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in borders'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.21 fills CT_Fills */ | ||||
| function parse_fills(t, styles, opts) { | ||||
| function parse_fills(t, styles, themes, opts) { | ||||
| 	styles.Fills = []; | ||||
| 	var fill = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| @ -11,9 +74,12 @@ function parse_fills(t, styles, opts) { | ||||
| 			case '<fill>': break; | ||||
| 			case '</fill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.24 gradientFill CT_GradientFill */ | ||||
| 			case '<fill>': break; | ||||
| 			case '</fill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.32 patternFill CT_PatternFill */ | ||||
| 			case '<patternFill': | ||||
| 			case '<patternFill>': | ||||
| 			case '<patternFill': case '<patternFill>': | ||||
| 				if(y.patternType) fill.patternType = y.patternType; | ||||
| 				break; | ||||
| 			case '<patternFill/>': case '</patternFill>': break; | ||||
| @ -25,7 +91,7 @@ function parse_fills(t, styles, opts) { | ||||
| 				if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10); | ||||
| 				if(y.tint) fill.bgColor.tint = parseFloat(y.tint); | ||||
| 				/* Excel uses ARGB strings */ | ||||
| 				if(y.rgb) fill.bgColor.rgb = y.rgb.substring(y.rgb.length - 6); | ||||
| 				if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6); | ||||
| 				break; | ||||
| 			case '<bgColor/>': case '</bgColor>': break; | ||||
| 
 | ||||
| @ -35,15 +101,104 @@ function parse_fills(t, styles, opts) { | ||||
| 				if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10); | ||||
| 				if(y.tint) fill.fgColor.tint = parseFloat(y.tint); | ||||
| 				/* Excel uses ARGB strings */ | ||||
| 				if(y.rgb) fill.fgColor.rgb = y.rgb.substring(y.rgb.length - 6); | ||||
| 				if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6); | ||||
| 				break; | ||||
| 			case '<fgColor/>': case '</fgColor>': break; | ||||
| 
 | ||||
| 			/* 18.8.38 stop CT_GradientStop */ | ||||
| 			case '<stop': case '<stop/>': break; | ||||
| 			case '</stop>': break; | ||||
| 
 | ||||
| 			/* 18.8.? color CT_Color */ | ||||
| 			case '<color': case '<color/>': break; | ||||
| 			case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fills'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.23 fonts CT_Fonts */ | ||||
| function parse_fonts(t, styles, themes, opts) { | ||||
| 	styles.Fonts = []; | ||||
| 	var font = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch (y[0]) { | ||||
| 			case '<fonts': case '<fonts>': case '</fonts>': break; | ||||
| 
 | ||||
| 			/* 18.8.22 font CT_Font */ | ||||
| 			case '<font': case '<font>': break; | ||||
| 			case '</font>': case '<font/>': | ||||
| 				styles.Fonts.push(font); | ||||
| 				font = {}; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.8.29 name CT_FontName */ | ||||
| 			case '<name': if(y.val) font.name = y.val; break; | ||||
| 			case '<name/>': case '</name>': break; | ||||
| 
 | ||||
| 			/* 18.8.2 b CT_BooleanProperty */ | ||||
| 			case '<b': break; // TODO: read val (0 = off)
 | ||||
| 			case '<b/>': font.bold = true; break; | ||||
| 
 | ||||
| 			/* 18.8.26 i CT_BooleanProperty */ | ||||
| 			case '<i': break; // TODO: read val (0 = off)
 | ||||
| 			case '<i/>': font.italic = true; break; | ||||
| 
 | ||||
| 			/* 18.4.13 u CT_UnderlineProperty */ | ||||
| 			case '<u': font.underline = true; break; // TODO: double underline
 | ||||
| 			case '<u/>': font.underline = true; break; | ||||
| 
 | ||||
| 			/* 18.4.10 strike CT_BooleanProperty */ | ||||
| 			case '<strike': break; // TODO: read val (0 = off)
 | ||||
| 			case '<strike/>': font.strike = true; break; | ||||
| 
 | ||||
| 			/* 18.4.2 outline CT_BooleanProperty */ | ||||
| 			case '<outline/>': font.outline = true; break; | ||||
| 
 | ||||
| 			/* 18.8.36 shadow CT_BooleanProperty */ | ||||
| 			case '<shadow/>': font.shadow = true; break; | ||||
| 
 | ||||
| 			/* 18.4.11 sz CT_FontSize */ | ||||
| 			case '<sz': if(y.val) font.sz = y.val; break; | ||||
| 			case '<sz/>': case '</sz>': break; | ||||
| 
 | ||||
| 			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */ | ||||
| 			case '<vertAlign': if(y.val) font.vertAlign = y.val; break; | ||||
| 			case '<vertAlign/>': case '</vertAlign>': break; | ||||
| 
 | ||||
| 			/* 18.8.18 family CT_FontFamily */ | ||||
| 			case '<family': if(y.val) font.family = y.val; break; | ||||
| 			case '<family/>': case '</family>': break; | ||||
| 
 | ||||
| 			/* 18.8.35 scheme CT_FontScheme */ | ||||
| 			case '<scheme': if(y.val) font.scheme = y.val; break; | ||||
| 			case '<scheme/>': case '</scheme>': break; | ||||
| 
 | ||||
| 			/* 18.4.1 charset CT_IntProperty TODO */ | ||||
| 			case '<charset': | ||||
| 				if(y.val == '1') break; | ||||
| 				y.codepage = CS2CP[parseInt(y.val, 10)]; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.?.? color CT_Color TODO */ | ||||
| 			case '<color': | ||||
| 				if(!font.color) font.color = {}; | ||||
| 				if(y.theme) font.color.theme = y.theme; | ||||
| 				if(y.tint) font.color.tint = y.tint; | ||||
| 				if(y.theme && themes.themeElements && themes.themeElements.clrScheme) { | ||||
| 					font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0); | ||||
| 				} | ||||
| 				if(y.rgb) font.color.rgb = y.rgb; | ||||
| 				break; | ||||
| 			case '<color/>': case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fonts'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.31 numFmts CT_NumFmts */ | ||||
| function parse_numFmts(t, styles, opts) { | ||||
| 	styles.NumberFmt = []; | ||||
| @ -68,7 +223,7 @@ function parse_numFmts(t, styles, opts) { | ||||
| function write_numFmts(NF/*:{[n:number]:string}*/, opts) { | ||||
| 	var o = ["<numFmts>"]; | ||||
| 	[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) { | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i]) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| 	}); | ||||
| 	if(o.length === 1) return ""; | ||||
| 	o[o.length] = ("</numFmts>"); | ||||
| @ -79,24 +234,37 @@ function write_numFmts(NF/*:{[n:number]:string}*/, opts) { | ||||
| /* 18.8.10 cellXfs CT_CellXfs */ | ||||
| function parse_cellXfs(t, styles, opts) { | ||||
| 	styles.CellXf = []; | ||||
| 	var xf; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch(y[0]) { | ||||
| 			case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break; | ||||
| 
 | ||||
| 			/* 18.8.45 xf CT_Xf */ | ||||
| 			case '<xf': delete y[0]; | ||||
| 				if(y.numFmtId) y.numFmtId = parseInt(y.numFmtId, 10); | ||||
| 				if(y.fillId) y.fillId = parseInt(y.fillId, 10); | ||||
| 				styles.CellXf.push(y); break; | ||||
| 			case '<xf': | ||||
| 				xf = y; | ||||
| 				delete xf[0]; | ||||
| 				if(xf.numFmtId) xf.numFmtId = parseInt(xf.numFmtId, 10); | ||||
| 				if(xf.fillId) xf.fillId = parseInt(xf.fillId, 10); | ||||
| 				styles.CellXf.push(xf); break; | ||||
| 			case '</xf>': break; | ||||
| 
 | ||||
| 			/* 18.8.1 alignment CT_CellAlignment */ | ||||
| 			case '<alignment': case '<alignment/>': case '</alignment>': break; | ||||
| 			case '<alignment': case '<alignment/>': | ||||
| 				var alignment = {}; | ||||
| 				if(y.vertical) alignment.vertical = y.vertical; | ||||
| 				if(y.horizontal) alignment.horizontal = y.horizontal; | ||||
| 				if(y.textRotation != null) alignment.textRotation = y.textRotation; | ||||
| 				if(y.indent) alignment.indent = y.indent; | ||||
| 				if(y.wrapText) alignment.wrapText = y.wrapText; | ||||
| 				xf.alignment = alignment; | ||||
| 				break; | ||||
| 			case '</alignment>': break; | ||||
| 
 | ||||
| 			/* 18.8.33 protection CT_CellProtection */ | ||||
| 			case '<protection': case '</protection>': case '<protection/>': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '</extLst>': break; | ||||
| 			case '<ext': break; | ||||
| 			default: if(opts.WTF) throw 'unrecognized ' + y[0] + ' in cellXfs'; | ||||
| @ -119,32 +287,36 @@ var parse_sty_xml= (function make_pstyx() { | ||||
| var numFmtRegex = /<numFmts([^>]*)>.*<\/numFmts>/; | ||||
| var cellXfRegex = /<cellXfs([^>]*)>.*<\/cellXfs>/; | ||||
| var fillsRegex = /<fills([^>]*)>.*<\/fills>/; | ||||
| var fontsRegex = /<fonts([^>]*)>.*<\/fonts>/; | ||||
| var bordersRegex = /<borders([^>]*)>.*<\/borders>/; | ||||
| 
 | ||||
| return function parse_sty_xml(data, opts) { | ||||
| return function parse_sty_xml(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	if(!data) return styles; | ||||
| 	/* 18.8.39 styleSheet CT_Stylesheet */ | ||||
| 	var t; | ||||
| 
 | ||||
| 	/* numFmts CT_NumFmts ? */ | ||||
| 	/* 18.8.31 numFmts CT_NumFmts ? */ | ||||
| 	if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts); | ||||
| 
 | ||||
| 	/* fonts CT_Fonts ? */ | ||||
| 	/*if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);*/ | ||||
| 	/* 18.8.23 fonts CT_Fonts ? */ | ||||
| 	if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* fills CT_Fills */ | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, opts); | ||||
| 	/* 18.8.21 fills CT_Fills */ | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* borders CT_Borders ? */ | ||||
| 	/* cellStyleXfs CT_CellStyleXfs ? */ | ||||
| 	/* 18.8.5 borders CT_Borders ? */ | ||||
| 	if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* cellXfs CT_CellXfs ? */ | ||||
| 	/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */ | ||||
| 
 | ||||
| 	/* 18.8.10 cellXfs CT_CellXfs ? */ | ||||
| 	if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts); | ||||
| 
 | ||||
| 	/* dxfs CT_Dxfs ? */ | ||||
| 	/* tableStyles CT_TableStyles ? */ | ||||
| 	/* colors CT_Colors ? */ | ||||
| 	/* extLst CT_ExtensionList ? */ | ||||
| 	/* 18.8.15 dxfs CT_Dxfs ? */ | ||||
| 	/* 18.8.42 tableStyles CT_TableStyles ? */ | ||||
| 	/* 18.8.11 colors CT_Colors ? */ | ||||
| 	/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 
 | ||||
| 	return styles; | ||||
| }; | ||||
|  | ||||
| @ -41,7 +41,7 @@ function parse_BrtXF(data, length/*:number*/) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.50 Styles */ | ||||
| function parse_sty_bin(data, opts) { | ||||
| function parse_sty_bin(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	styles.NumberFmt = ([]/*:any*/); | ||||
| 	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; | ||||
|  | ||||
| @ -8,9 +8,9 @@ function parse_ws(data, name/*:string*/, opts, rels, wb, themes, styles)/*:Works | ||||
| 	return parse_ws_xml((data/*:any*/), opts, rels, wb, themes, styles); | ||||
| } | ||||
| 
 | ||||
| function parse_sty(data, name/*:string*/, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_sty_bin((data/*:any*/), opts); | ||||
| 	return parse_sty_xml((data/*:any*/), opts); | ||||
| function parse_sty(data, name/*:string*/, themes, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_sty_bin((data/*:any*/), themes, opts); | ||||
| 	return parse_sty_xml((data/*:any*/), themes, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_theme(data/*:string*/, name/*:string*/, opts) { | ||||
|  | ||||
| @ -48,9 +48,9 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		strs = []; | ||||
| 		if(dir.sst) strs=parse_sst(getzipdata(zip, dir.sst.replace(/^\//,'')), dir.sst, opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, dir.style.replace(/^\//,'')),dir.style, opts); | ||||
| 
 | ||||
| 		if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, dir.style.replace(/^\//,'')),dir.style, themes, opts); | ||||
| 	} | ||||
| 
 | ||||
| 	var wb = parse_wb(getzipdata(zip, dir.workbooks[0].replace(/^\//,'')), dir.workbooks[0], opts); | ||||
|  | ||||
							
								
								
									
										79
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										79
									
								
								test.js
									
									
									
									
									
								
							| @ -191,7 +191,10 @@ describe('should parse test files', function() { | ||||
| 			it(x + ' [' + ext + ']', function(){ | ||||
| 				var wb = wbtable[dir + x]; | ||||
| 				if(!wb) wb = X.readFile(dir + x, opts); | ||||
| 				parsetest(x, X.read(X.write(wb, {type:"buffer", bookType:ext.replace(/\./,"")}), {WTF:opts.WTF}), ext.replace(/\./,"") !== "xlsb", ext); | ||||
| 
 | ||||
| 				wb = X.read(X.write(wb, {type:"buffer", bookType:ext.replace(/\./,"")}), {WTF:opts.WTF, cellNF: true}); | ||||
| 
 | ||||
| 				parsetest(x, wb, ext.replace(/\./,"") !== "xlsb", ext); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| @ -292,7 +295,7 @@ describe('parse options', function() { | ||||
| 		}); | ||||
| 		it('should generate cell styles when requested', function() { | ||||
| 			/* TODO: XLS / XLML */ | ||||
| 			[paths.cssxlsx, /*paths.cssxls, paths.cssxml*/].forEach(function(p) { | ||||
| 			[paths.cssxlsx /*,paths.cssxls, paths.cssxml*/].forEach(function(p) { | ||||
| 			var wb = X.readFile(p, {cellStyles:true}); | ||||
| 			var found = false; | ||||
| 			wb.SheetNames.forEach(function(s) { | ||||
| @ -774,31 +777,31 @@ describe('parse features', function() { | ||||
| 			'H1:J4', 'H10' /* blocks */ | ||||
| 		]; | ||||
| 		var exp = [ | ||||
|   { patternType: 'darkHorizontal', | ||||
|     fgColor: { theme: 9, raw_rgb: 'F79646' }, | ||||
|     bgColor: { theme: 5, raw_rgb: 'C0504D' } }, | ||||
|   { patternType: 'darkUp', | ||||
|     fgColor: { theme: 3, raw_rgb: 'EEECE1' }, | ||||
|     bgColor: { theme: 7, raw_rgb: '8064A2' } }, | ||||
|   { patternType: 'darkGray', | ||||
|     fgColor: { theme: 3, raw_rgb: 'EEECE1' }, | ||||
|     bgColor: { theme: 1, raw_rgb: 'FFFFFF' } }, | ||||
|   { patternType: 'lightGray', | ||||
|     fgColor: { theme: 6, raw_rgb: '9BBB59' }, | ||||
|     bgColor: { theme: 2, raw_rgb: '1F497D' } }, | ||||
|   { patternType: 'lightDown', | ||||
|     fgColor: { theme: 4, raw_rgb: '4F81BD' }, | ||||
|     bgColor: { theme: 7, raw_rgb: '8064A2' } }, | ||||
|   { patternType: 'lightGrid', | ||||
|     fgColor: { theme: 6, raw_rgb: '9BBB59' }, | ||||
|     bgColor: { theme: 9, raw_rgb: 'F79646' } }, | ||||
|   { patternType: 'lightGrid', | ||||
|     fgColor: { theme: 4, raw_rgb: '4F81BD' }, | ||||
|     bgColor: { theme: 2, raw_rgb: '1F497D' } }, | ||||
|   { patternType: 'lightVertical', | ||||
|     fgColor: { theme: 3, raw_rgb: 'EEECE1' }, | ||||
|     bgColor: { theme: 7, raw_rgb: '8064A2' } } | ||||
|     ]; | ||||
| 			{ patternType: 'darkHorizontal', | ||||
| 			  fgColor: { theme: 9, raw_rgb: 'F79646' }, | ||||
| 			  bgColor: { theme: 5, raw_rgb: 'C0504D' } }, | ||||
| 			{ patternType: 'darkUp', | ||||
| 			  fgColor: { theme: 3, raw_rgb: 'EEECE1' }, | ||||
| 			  bgColor: { theme: 7, raw_rgb: '8064A2' } }, | ||||
| 			{ patternType: 'darkGray', | ||||
| 			  fgColor: { theme: 3, raw_rgb: 'EEECE1' }, | ||||
| 			  bgColor: { theme: 1, raw_rgb: 'FFFFFF' } }, | ||||
| 			{ patternType: 'lightGray', | ||||
| 			  fgColor: { theme: 6, raw_rgb: '9BBB59' }, | ||||
| 			  bgColor: { theme: 2, raw_rgb: '1F497D' } }, | ||||
| 			{ patternType: 'lightDown', | ||||
| 			  fgColor: { theme: 4, raw_rgb: '4F81BD' }, | ||||
| 			  bgColor: { theme: 7, raw_rgb: '8064A2' } }, | ||||
| 			{ patternType: 'lightGrid', | ||||
| 			  fgColor: { theme: 6, raw_rgb: '9BBB59' }, | ||||
| 			  bgColor: { theme: 9, raw_rgb: 'F79646' } }, | ||||
| 			{ patternType: 'lightGrid', | ||||
| 			  fgColor: { theme: 4, raw_rgb: '4F81BD' }, | ||||
| 			  bgColor: { theme: 2, raw_rgb: '1F497D' } }, | ||||
| 			{ patternType: 'lightVertical', | ||||
| 			  fgColor: { theme: 3, raw_rgb: 'EEECE1' }, | ||||
| 			  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; }));}); | ||||
| @ -1172,17 +1175,17 @@ describe('corner cases', function() { | ||||
| 			assert.doesNotThrow(function(x) { return X.SSF.format(f, 12345.6789);}); | ||||
| 		}); | ||||
| 	}); | ||||
|   it('SSF oddities', function() { | ||||
|     var ssfdata = require('./misc/ssf.json'); | ||||
|     ssfdata.forEach(function(d) { | ||||
|       for(var j=1;j<d.length;++j) { | ||||
|         if(d[j].length == 2) { | ||||
|           var expected = d[j][1], actual = X.SSF.format(d[0], d[j][0], {}); | ||||
|           assert.equal(actual, expected); | ||||
|         } else if(d[j][2] !== "#") assert.throws(function() { SSF.format(d[0], d[j][0]); }); | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| 	it('SSF oddities', function() { | ||||
| 		var ssfdata = require('./misc/ssf.json'); | ||||
| 		ssfdata.forEach(function(d) { | ||||
| 			for(var j=1;j<d.length;++j) { | ||||
| 				if(d[j].length == 2) { | ||||
| 					var expected = d[j][1], actual = X.SSF.format(d[0], d[j][0], {}); | ||||
| 					assert.equal(actual, expected); | ||||
| 				} else if(d[j][2] !== "#") assert.throws(function() { SSF.format(d[0], d[j][0]); }); | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| 	it('CFB', function() { | ||||
| 		var cfb = X.CFB.read(paths.swcxls, {type:"file"}); | ||||
| 		var xls = X.parse_xlscfb(cfb); | ||||
|  | ||||
							
								
								
									
										232
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										232
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -5071,8 +5071,71 @@ var XLMLPatternTypeMap = { | ||||
| 	"ThinHorzCross": "lightGrid" | ||||
| }; | ||||
| 
 | ||||
| /* 18.8.5 borders CT_Borders */ | ||||
| function parse_borders(t, styles, themes, opts) { | ||||
| 	styles.Borders = []; | ||||
| 	var border = {}, sub_border = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch (y[0]) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| 
 | ||||
| 			/* 18.8.4 border CT_Border */ | ||||
| 			case '<border': case '<border>': | ||||
| 				border = {}; | ||||
| 				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; } | ||||
| 				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; } | ||||
| 				styles.Borders.push(border); | ||||
| 				break; | ||||
| 			case '</border>': break; | ||||
| 
 | ||||
| 			/* note: not in spec, appears to be CT_BorderPr */ | ||||
| 			case '<left': case '<left/>': break; | ||||
| 			case '</left>': break; | ||||
| 
 | ||||
| 			/* note: not in spec, appears to be CT_BorderPr */ | ||||
| 			case '<right': case '<right/>': break; | ||||
| 			case '</right>': break; | ||||
| 
 | ||||
| 			/* 18.8.43 top CT_BorderPr */ | ||||
| 			case '<top': case '<top/>': break; | ||||
| 			case '</top>': break; | ||||
| 
 | ||||
| 			/* 18.8.6 bottom CT_BorderPr */ | ||||
| 			case '<bottom': case '<bottom/>': break; | ||||
| 			case '</bottom>': break; | ||||
| 
 | ||||
| 			/* 18.8.13 diagonal CT_BorderPr */ | ||||
| 			case '<diagonal': case '<diagonal/>': break; | ||||
| 			case '</diagonal>': break; | ||||
| 
 | ||||
| 			/* 18.8.25 horizontal CT_BorderPr */ | ||||
| 			case '<horizontal': case '<horizontal/>': break; | ||||
| 			case '</horizontal>': break; | ||||
| 
 | ||||
| 			/* 18.8.44 vertical CT_BorderPr */ | ||||
| 			case '<vertical': case '<vertical/>': break; | ||||
| 			case '</vertical>': break; | ||||
| 
 | ||||
| 			/* 18.8.37 start CT_BorderPr */ | ||||
| 			case '<start': case '<start/>': break; | ||||
| 			case '</start>': break; | ||||
| 
 | ||||
| 			/* 18.8.16 end CT_BorderPr */ | ||||
| 			case '<end': case '<end/>': break; | ||||
| 			case '</end>': break; | ||||
| 
 | ||||
| 			/* 18.8.? color CT_Color */ | ||||
| 			case '<color': case '<color/>': break; | ||||
| 			case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in borders'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.21 fills CT_Fills */ | ||||
| function parse_fills(t, styles, opts) { | ||||
| function parse_fills(t, styles, themes, opts) { | ||||
| 	styles.Fills = []; | ||||
| 	var fill = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| @ -5084,9 +5147,12 @@ function parse_fills(t, styles, opts) { | ||||
| 			case '<fill>': break; | ||||
| 			case '</fill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.24 gradientFill CT_GradientFill */ | ||||
| 			case '<fill>': break; | ||||
| 			case '</fill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.32 patternFill CT_PatternFill */ | ||||
| 			case '<patternFill': | ||||
| 			case '<patternFill>': | ||||
| 			case '<patternFill': case '<patternFill>': | ||||
| 				if(y.patternType) fill.patternType = y.patternType; | ||||
| 				break; | ||||
| 			case '<patternFill/>': case '</patternFill>': break; | ||||
| @ -5098,7 +5164,7 @@ function parse_fills(t, styles, opts) { | ||||
| 				if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10); | ||||
| 				if(y.tint) fill.bgColor.tint = parseFloat(y.tint); | ||||
| 				/* Excel uses ARGB strings */ | ||||
| 				if(y.rgb) fill.bgColor.rgb = y.rgb.substring(y.rgb.length - 6); | ||||
| 				if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6); | ||||
| 				break; | ||||
| 			case '<bgColor/>': case '</bgColor>': break; | ||||
| 
 | ||||
| @ -5108,15 +5174,104 @@ function parse_fills(t, styles, opts) { | ||||
| 				if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10); | ||||
| 				if(y.tint) fill.fgColor.tint = parseFloat(y.tint); | ||||
| 				/* Excel uses ARGB strings */ | ||||
| 				if(y.rgb) fill.fgColor.rgb = y.rgb.substring(y.rgb.length - 6); | ||||
| 				if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6); | ||||
| 				break; | ||||
| 			case '<fgColor/>': case '</fgColor>': break; | ||||
| 
 | ||||
| 			/* 18.8.38 stop CT_GradientStop */ | ||||
| 			case '<stop': case '<stop/>': break; | ||||
| 			case '</stop>': break; | ||||
| 
 | ||||
| 			/* 18.8.? color CT_Color */ | ||||
| 			case '<color': case '<color/>': break; | ||||
| 			case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fills'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.23 fonts CT_Fonts */ | ||||
| function parse_fonts(t, styles, themes, opts) { | ||||
| 	styles.Fonts = []; | ||||
| 	var font = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch (y[0]) { | ||||
| 			case '<fonts': case '<fonts>': case '</fonts>': break; | ||||
| 
 | ||||
| 			/* 18.8.22 font CT_Font */ | ||||
| 			case '<font': case '<font>': break; | ||||
| 			case '</font>': case '<font/>': | ||||
| 				styles.Fonts.push(font); | ||||
| 				font = {}; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.8.29 name CT_FontName */ | ||||
| 			case '<name': if(y.val) font.name = y.val; break; | ||||
| 			case '<name/>': case '</name>': break; | ||||
| 
 | ||||
| 			/* 18.8.2 b CT_BooleanProperty */ | ||||
| 			case '<b': break; // TODO: read val (0 = off)
 | ||||
| 			case '<b/>': font.bold = true; break; | ||||
| 
 | ||||
| 			/* 18.8.26 i CT_BooleanProperty */ | ||||
| 			case '<i': break; // TODO: read val (0 = off)
 | ||||
| 			case '<i/>': font.italic = true; break; | ||||
| 
 | ||||
| 			/* 18.4.13 u CT_UnderlineProperty */ | ||||
| 			case '<u': font.underline = true; break; // TODO: double underline
 | ||||
| 			case '<u/>': font.underline = true; break; | ||||
| 
 | ||||
| 			/* 18.4.10 strike CT_BooleanProperty */ | ||||
| 			case '<strike': break; // TODO: read val (0 = off)
 | ||||
| 			case '<strike/>': font.strike = true; break; | ||||
| 
 | ||||
| 			/* 18.4.2 outline CT_BooleanProperty */ | ||||
| 			case '<outline/>': font.outline = true; break; | ||||
| 
 | ||||
| 			/* 18.8.36 shadow CT_BooleanProperty */ | ||||
| 			case '<shadow/>': font.shadow = true; break; | ||||
| 
 | ||||
| 			/* 18.4.11 sz CT_FontSize */ | ||||
| 			case '<sz': if(y.val) font.sz = y.val; break; | ||||
| 			case '<sz/>': case '</sz>': break; | ||||
| 
 | ||||
| 			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */ | ||||
| 			case '<vertAlign': if(y.val) font.vertAlign = y.val; break; | ||||
| 			case '<vertAlign/>': case '</vertAlign>': break; | ||||
| 
 | ||||
| 			/* 18.8.18 family CT_FontFamily */ | ||||
| 			case '<family': if(y.val) font.family = y.val; break; | ||||
| 			case '<family/>': case '</family>': break; | ||||
| 
 | ||||
| 			/* 18.8.35 scheme CT_FontScheme */ | ||||
| 			case '<scheme': if(y.val) font.scheme = y.val; break; | ||||
| 			case '<scheme/>': case '</scheme>': break; | ||||
| 
 | ||||
| 			/* 18.4.1 charset CT_IntProperty TODO */ | ||||
| 			case '<charset': | ||||
| 				if(y.val == '1') break; | ||||
| 				y.codepage = CS2CP[parseInt(y.val, 10)]; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.?.? color CT_Color TODO */ | ||||
| 			case '<color': | ||||
| 				if(!font.color) font.color = {}; | ||||
| 				if(y.theme) font.color.theme = y.theme; | ||||
| 				if(y.tint) font.color.tint = y.tint; | ||||
| 				if(y.theme && themes.themeElements && themes.themeElements.clrScheme) { | ||||
| 					font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0); | ||||
| 				} | ||||
| 				if(y.rgb) font.color.rgb = y.rgb; | ||||
| 				break; | ||||
| 			case '<color/>': case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fonts'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.31 numFmts CT_NumFmts */ | ||||
| function parse_numFmts(t, styles, opts) { | ||||
| 	styles.NumberFmt = []; | ||||
| @ -5141,7 +5296,7 @@ function parse_numFmts(t, styles, opts) { | ||||
| function write_numFmts(NF/*:{[n:number]:string}*/, opts) { | ||||
| 	var o = ["<numFmts>"]; | ||||
| 	[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) { | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i]) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| 	}); | ||||
| 	if(o.length === 1) return ""; | ||||
| 	o[o.length] = ("</numFmts>"); | ||||
| @ -5152,24 +5307,37 @@ function write_numFmts(NF/*:{[n:number]:string}*/, opts) { | ||||
| /* 18.8.10 cellXfs CT_CellXfs */ | ||||
| function parse_cellXfs(t, styles, opts) { | ||||
| 	styles.CellXf = []; | ||||
| 	var xf; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch(y[0]) { | ||||
| 			case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break; | ||||
| 
 | ||||
| 			/* 18.8.45 xf CT_Xf */ | ||||
| 			case '<xf': delete y[0]; | ||||
| 				if(y.numFmtId) y.numFmtId = parseInt(y.numFmtId, 10); | ||||
| 				if(y.fillId) y.fillId = parseInt(y.fillId, 10); | ||||
| 				styles.CellXf.push(y); break; | ||||
| 			case '<xf': | ||||
| 				xf = y; | ||||
| 				delete xf[0]; | ||||
| 				if(xf.numFmtId) xf.numFmtId = parseInt(xf.numFmtId, 10); | ||||
| 				if(xf.fillId) xf.fillId = parseInt(xf.fillId, 10); | ||||
| 				styles.CellXf.push(xf); break; | ||||
| 			case '</xf>': break; | ||||
| 
 | ||||
| 			/* 18.8.1 alignment CT_CellAlignment */ | ||||
| 			case '<alignment': case '<alignment/>': case '</alignment>': break; | ||||
| 			case '<alignment': case '<alignment/>': | ||||
| 				var alignment = {}; | ||||
| 				if(y.vertical) alignment.vertical = y.vertical; | ||||
| 				if(y.horizontal) alignment.horizontal = y.horizontal; | ||||
| 				if(y.textRotation != null) alignment.textRotation = y.textRotation; | ||||
| 				if(y.indent) alignment.indent = y.indent; | ||||
| 				if(y.wrapText) alignment.wrapText = y.wrapText; | ||||
| 				xf.alignment = alignment; | ||||
| 				break; | ||||
| 			case '</alignment>': break; | ||||
| 
 | ||||
| 			/* 18.8.33 protection CT_CellProtection */ | ||||
| 			case '<protection': case '</protection>': case '<protection/>': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '</extLst>': break; | ||||
| 			case '<ext': break; | ||||
| 			default: if(opts.WTF) throw 'unrecognized ' + y[0] + ' in cellXfs'; | ||||
| @ -5192,32 +5360,36 @@ var parse_sty_xml= (function make_pstyx() { | ||||
| var numFmtRegex = /<numFmts([^>]*)>.*<\/numFmts>/; | ||||
| var cellXfRegex = /<cellXfs([^>]*)>.*<\/cellXfs>/; | ||||
| var fillsRegex = /<fills([^>]*)>.*<\/fills>/; | ||||
| var fontsRegex = /<fonts([^>]*)>.*<\/fonts>/; | ||||
| var bordersRegex = /<borders([^>]*)>.*<\/borders>/; | ||||
| 
 | ||||
| return function parse_sty_xml(data, opts) { | ||||
| return function parse_sty_xml(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	if(!data) return styles; | ||||
| 	/* 18.8.39 styleSheet CT_Stylesheet */ | ||||
| 	var t; | ||||
| 
 | ||||
| 	/* numFmts CT_NumFmts ? */ | ||||
| 	/* 18.8.31 numFmts CT_NumFmts ? */ | ||||
| 	if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts); | ||||
| 
 | ||||
| 	/* fonts CT_Fonts ? */ | ||||
| 	/*if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);*/ | ||||
| 	/* 18.8.23 fonts CT_Fonts ? */ | ||||
| 	if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* fills CT_Fills */ | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, opts); | ||||
| 	/* 18.8.21 fills CT_Fills */ | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* borders CT_Borders ? */ | ||||
| 	/* cellStyleXfs CT_CellStyleXfs ? */ | ||||
| 	/* 18.8.5 borders CT_Borders ? */ | ||||
| 	if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* cellXfs CT_CellXfs ? */ | ||||
| 	/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */ | ||||
| 
 | ||||
| 	/* 18.8.10 cellXfs CT_CellXfs ? */ | ||||
| 	if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts); | ||||
| 
 | ||||
| 	/* dxfs CT_Dxfs ? */ | ||||
| 	/* tableStyles CT_TableStyles ? */ | ||||
| 	/* colors CT_Colors ? */ | ||||
| 	/* extLst CT_ExtensionList ? */ | ||||
| 	/* 18.8.15 dxfs CT_Dxfs ? */ | ||||
| 	/* 18.8.42 tableStyles CT_TableStyles ? */ | ||||
| 	/* 18.8.11 colors CT_Colors ? */ | ||||
| 	/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 
 | ||||
| 	return styles; | ||||
| }; | ||||
| @ -5288,7 +5460,7 @@ function parse_BrtXF(data, length/*:number*/) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.50 Styles */ | ||||
| function parse_sty_bin(data, opts) { | ||||
| function parse_sty_bin(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	styles.NumberFmt = ([]/*:any*/); | ||||
| 	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; | ||||
| @ -9707,9 +9879,9 @@ function parse_ws(data, name/*:string*/, opts, rels, wb, themes, styles)/*:Works | ||||
| 	return parse_ws_xml((data/*:any*/), opts, rels, wb, themes, styles); | ||||
| } | ||||
| 
 | ||||
| function parse_sty(data, name/*:string*/, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_sty_bin((data/*:any*/), opts); | ||||
| 	return parse_sty_xml((data/*:any*/), opts); | ||||
| function parse_sty(data, name/*:string*/, themes, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_sty_bin((data/*:any*/), themes, opts); | ||||
| 	return parse_sty_xml((data/*:any*/), themes, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_theme(data/*:string*/, name/*:string*/, opts) { | ||||
| @ -13337,9 +13509,9 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		strs = []; | ||||
| 		if(dir.sst) strs=parse_sst(getzipdata(zip, dir.sst.replace(/^\//,'')), dir.sst, opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, dir.style.replace(/^\//,'')),dir.style, opts); | ||||
| 
 | ||||
| 		if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, dir.style.replace(/^\//,'')),dir.style, themes, opts); | ||||
| 	} | ||||
| 
 | ||||
| 	var wb = parse_wb(getzipdata(zip, dir.workbooks[0].replace(/^\//,'')), dir.workbooks[0], opts); | ||||
|  | ||||
							
								
								
									
										232
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										232
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -5019,8 +5019,71 @@ var XLMLPatternTypeMap = { | ||||
| 	"ThinHorzCross": "lightGrid" | ||||
| }; | ||||
| 
 | ||||
| /* 18.8.5 borders CT_Borders */ | ||||
| function parse_borders(t, styles, themes, opts) { | ||||
| 	styles.Borders = []; | ||||
| 	var border = {}, sub_border = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch (y[0]) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| 
 | ||||
| 			/* 18.8.4 border CT_Border */ | ||||
| 			case '<border': case '<border>': | ||||
| 				border = {}; | ||||
| 				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; } | ||||
| 				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; } | ||||
| 				styles.Borders.push(border); | ||||
| 				break; | ||||
| 			case '</border>': break; | ||||
| 
 | ||||
| 			/* note: not in spec, appears to be CT_BorderPr */ | ||||
| 			case '<left': case '<left/>': break; | ||||
| 			case '</left>': break; | ||||
| 
 | ||||
| 			/* note: not in spec, appears to be CT_BorderPr */ | ||||
| 			case '<right': case '<right/>': break; | ||||
| 			case '</right>': break; | ||||
| 
 | ||||
| 			/* 18.8.43 top CT_BorderPr */ | ||||
| 			case '<top': case '<top/>': break; | ||||
| 			case '</top>': break; | ||||
| 
 | ||||
| 			/* 18.8.6 bottom CT_BorderPr */ | ||||
| 			case '<bottom': case '<bottom/>': break; | ||||
| 			case '</bottom>': break; | ||||
| 
 | ||||
| 			/* 18.8.13 diagonal CT_BorderPr */ | ||||
| 			case '<diagonal': case '<diagonal/>': break; | ||||
| 			case '</diagonal>': break; | ||||
| 
 | ||||
| 			/* 18.8.25 horizontal CT_BorderPr */ | ||||
| 			case '<horizontal': case '<horizontal/>': break; | ||||
| 			case '</horizontal>': break; | ||||
| 
 | ||||
| 			/* 18.8.44 vertical CT_BorderPr */ | ||||
| 			case '<vertical': case '<vertical/>': break; | ||||
| 			case '</vertical>': break; | ||||
| 
 | ||||
| 			/* 18.8.37 start CT_BorderPr */ | ||||
| 			case '<start': case '<start/>': break; | ||||
| 			case '</start>': break; | ||||
| 
 | ||||
| 			/* 18.8.16 end CT_BorderPr */ | ||||
| 			case '<end': case '<end/>': break; | ||||
| 			case '</end>': break; | ||||
| 
 | ||||
| 			/* 18.8.? color CT_Color */ | ||||
| 			case '<color': case '<color/>': break; | ||||
| 			case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in borders'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.21 fills CT_Fills */ | ||||
| function parse_fills(t, styles, opts) { | ||||
| function parse_fills(t, styles, themes, opts) { | ||||
| 	styles.Fills = []; | ||||
| 	var fill = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| @ -5032,9 +5095,12 @@ function parse_fills(t, styles, opts) { | ||||
| 			case '<fill>': break; | ||||
| 			case '</fill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.24 gradientFill CT_GradientFill */ | ||||
| 			case '<fill>': break; | ||||
| 			case '</fill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.32 patternFill CT_PatternFill */ | ||||
| 			case '<patternFill': | ||||
| 			case '<patternFill>': | ||||
| 			case '<patternFill': case '<patternFill>': | ||||
| 				if(y.patternType) fill.patternType = y.patternType; | ||||
| 				break; | ||||
| 			case '<patternFill/>': case '</patternFill>': break; | ||||
| @ -5046,7 +5112,7 @@ function parse_fills(t, styles, opts) { | ||||
| 				if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10); | ||||
| 				if(y.tint) fill.bgColor.tint = parseFloat(y.tint); | ||||
| 				/* Excel uses ARGB strings */ | ||||
| 				if(y.rgb) fill.bgColor.rgb = y.rgb.substring(y.rgb.length - 6); | ||||
| 				if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6); | ||||
| 				break; | ||||
| 			case '<bgColor/>': case '</bgColor>': break; | ||||
| 
 | ||||
| @ -5056,15 +5122,104 @@ function parse_fills(t, styles, opts) { | ||||
| 				if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10); | ||||
| 				if(y.tint) fill.fgColor.tint = parseFloat(y.tint); | ||||
| 				/* Excel uses ARGB strings */ | ||||
| 				if(y.rgb) fill.fgColor.rgb = y.rgb.substring(y.rgb.length - 6); | ||||
| 				if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6); | ||||
| 				break; | ||||
| 			case '<fgColor/>': case '</fgColor>': break; | ||||
| 
 | ||||
| 			/* 18.8.38 stop CT_GradientStop */ | ||||
| 			case '<stop': case '<stop/>': break; | ||||
| 			case '</stop>': break; | ||||
| 
 | ||||
| 			/* 18.8.? color CT_Color */ | ||||
| 			case '<color': case '<color/>': break; | ||||
| 			case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fills'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.23 fonts CT_Fonts */ | ||||
| function parse_fonts(t, styles, themes, opts) { | ||||
| 	styles.Fonts = []; | ||||
| 	var font = {}; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch (y[0]) { | ||||
| 			case '<fonts': case '<fonts>': case '</fonts>': break; | ||||
| 
 | ||||
| 			/* 18.8.22 font CT_Font */ | ||||
| 			case '<font': case '<font>': break; | ||||
| 			case '</font>': case '<font/>': | ||||
| 				styles.Fonts.push(font); | ||||
| 				font = {}; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.8.29 name CT_FontName */ | ||||
| 			case '<name': if(y.val) font.name = y.val; break; | ||||
| 			case '<name/>': case '</name>': break; | ||||
| 
 | ||||
| 			/* 18.8.2 b CT_BooleanProperty */ | ||||
| 			case '<b': break; // TODO: read val (0 = off)
 | ||||
| 			case '<b/>': font.bold = true; break; | ||||
| 
 | ||||
| 			/* 18.8.26 i CT_BooleanProperty */ | ||||
| 			case '<i': break; // TODO: read val (0 = off)
 | ||||
| 			case '<i/>': font.italic = true; break; | ||||
| 
 | ||||
| 			/* 18.4.13 u CT_UnderlineProperty */ | ||||
| 			case '<u': font.underline = true; break; // TODO: double underline
 | ||||
| 			case '<u/>': font.underline = true; break; | ||||
| 
 | ||||
| 			/* 18.4.10 strike CT_BooleanProperty */ | ||||
| 			case '<strike': break; // TODO: read val (0 = off)
 | ||||
| 			case '<strike/>': font.strike = true; break; | ||||
| 
 | ||||
| 			/* 18.4.2 outline CT_BooleanProperty */ | ||||
| 			case '<outline/>': font.outline = true; break; | ||||
| 
 | ||||
| 			/* 18.8.36 shadow CT_BooleanProperty */ | ||||
| 			case '<shadow/>': font.shadow = true; break; | ||||
| 
 | ||||
| 			/* 18.4.11 sz CT_FontSize */ | ||||
| 			case '<sz': if(y.val) font.sz = y.val; break; | ||||
| 			case '<sz/>': case '</sz>': break; | ||||
| 
 | ||||
| 			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */ | ||||
| 			case '<vertAlign': if(y.val) font.vertAlign = y.val; break; | ||||
| 			case '<vertAlign/>': case '</vertAlign>': break; | ||||
| 
 | ||||
| 			/* 18.8.18 family CT_FontFamily */ | ||||
| 			case '<family': if(y.val) font.family = y.val; break; | ||||
| 			case '<family/>': case '</family>': break; | ||||
| 
 | ||||
| 			/* 18.8.35 scheme CT_FontScheme */ | ||||
| 			case '<scheme': if(y.val) font.scheme = y.val; break; | ||||
| 			case '<scheme/>': case '</scheme>': break; | ||||
| 
 | ||||
| 			/* 18.4.1 charset CT_IntProperty TODO */ | ||||
| 			case '<charset': | ||||
| 				if(y.val == '1') break; | ||||
| 				y.codepage = CS2CP[parseInt(y.val, 10)]; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 18.?.? color CT_Color TODO */ | ||||
| 			case '<color': | ||||
| 				if(!font.color) font.color = {}; | ||||
| 				if(y.theme) font.color.theme = y.theme; | ||||
| 				if(y.tint) font.color.tint = y.tint; | ||||
| 				if(y.theme && themes.themeElements && themes.themeElements.clrScheme) { | ||||
| 					font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0); | ||||
| 				} | ||||
| 				if(y.rgb) font.color.rgb = y.rgb; | ||||
| 				break; | ||||
| 			case '<color/>': case '</color>': break; | ||||
| 
 | ||||
| 			default: if(opts && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in fonts'); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| /* 18.8.31 numFmts CT_NumFmts */ | ||||
| function parse_numFmts(t, styles, opts) { | ||||
| 	styles.NumberFmt = []; | ||||
| @ -5089,7 +5244,7 @@ function parse_numFmts(t, styles, opts) { | ||||
| function write_numFmts(NF, opts) { | ||||
| 	var o = ["<numFmts>"]; | ||||
| 	[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) { | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i]) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| 	}); | ||||
| 	if(o.length === 1) return ""; | ||||
| 	o[o.length] = ("</numFmts>"); | ||||
| @ -5100,24 +5255,37 @@ function write_numFmts(NF, opts) { | ||||
| /* 18.8.10 cellXfs CT_CellXfs */ | ||||
| function parse_cellXfs(t, styles, opts) { | ||||
| 	styles.CellXf = []; | ||||
| 	var xf; | ||||
| 	t[0].match(tagregex).forEach(function(x) { | ||||
| 		var y = parsexmltag(x); | ||||
| 		switch(y[0]) { | ||||
| 			case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break; | ||||
| 
 | ||||
| 			/* 18.8.45 xf CT_Xf */ | ||||
| 			case '<xf': delete y[0]; | ||||
| 				if(y.numFmtId) y.numFmtId = parseInt(y.numFmtId, 10); | ||||
| 				if(y.fillId) y.fillId = parseInt(y.fillId, 10); | ||||
| 				styles.CellXf.push(y); break; | ||||
| 			case '<xf': | ||||
| 				xf = y; | ||||
| 				delete xf[0]; | ||||
| 				if(xf.numFmtId) xf.numFmtId = parseInt(xf.numFmtId, 10); | ||||
| 				if(xf.fillId) xf.fillId = parseInt(xf.fillId, 10); | ||||
| 				styles.CellXf.push(xf); break; | ||||
| 			case '</xf>': break; | ||||
| 
 | ||||
| 			/* 18.8.1 alignment CT_CellAlignment */ | ||||
| 			case '<alignment': case '<alignment/>': case '</alignment>': break; | ||||
| 			case '<alignment': case '<alignment/>': | ||||
| 				var alignment = {}; | ||||
| 				if(y.vertical) alignment.vertical = y.vertical; | ||||
| 				if(y.horizontal) alignment.horizontal = y.horizontal; | ||||
| 				if(y.textRotation != null) alignment.textRotation = y.textRotation; | ||||
| 				if(y.indent) alignment.indent = y.indent; | ||||
| 				if(y.wrapText) alignment.wrapText = y.wrapText; | ||||
| 				xf.alignment = alignment; | ||||
| 				break; | ||||
| 			case '</alignment>': break; | ||||
| 
 | ||||
| 			/* 18.8.33 protection CT_CellProtection */ | ||||
| 			case '<protection': case '</protection>': case '<protection/>': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst': case '</extLst>': break; | ||||
| 			case '<ext': break; | ||||
| 			default: if(opts.WTF) throw 'unrecognized ' + y[0] + ' in cellXfs'; | ||||
| @ -5140,32 +5308,36 @@ var parse_sty_xml= (function make_pstyx() { | ||||
| var numFmtRegex = /<numFmts([^>]*)>.*<\/numFmts>/; | ||||
| var cellXfRegex = /<cellXfs([^>]*)>.*<\/cellXfs>/; | ||||
| var fillsRegex = /<fills([^>]*)>.*<\/fills>/; | ||||
| var fontsRegex = /<fonts([^>]*)>.*<\/fonts>/; | ||||
| var bordersRegex = /<borders([^>]*)>.*<\/borders>/; | ||||
| 
 | ||||
| return function parse_sty_xml(data, opts) { | ||||
| return function parse_sty_xml(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	if(!data) return styles; | ||||
| 	/* 18.8.39 styleSheet CT_Stylesheet */ | ||||
| 	var t; | ||||
| 
 | ||||
| 	/* numFmts CT_NumFmts ? */ | ||||
| 	/* 18.8.31 numFmts CT_NumFmts ? */ | ||||
| 	if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts); | ||||
| 
 | ||||
| 	/* fonts CT_Fonts ? */ | ||||
| 	/*if((t=data.match(/<fonts([^>]*)>.*<\/fonts>/))) parse_fonts(t, opts);*/ | ||||
| 	/* 18.8.23 fonts CT_Fonts ? */ | ||||
| 	if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* fills CT_Fills */ | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, opts); | ||||
| 	/* 18.8.21 fills CT_Fills */ | ||||
| 	if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* borders CT_Borders ? */ | ||||
| 	/* cellStyleXfs CT_CellStyleXfs ? */ | ||||
| 	/* 18.8.5 borders CT_Borders ? */ | ||||
| 	if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts); | ||||
| 
 | ||||
| 	/* cellXfs CT_CellXfs ? */ | ||||
| 	/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */ | ||||
| 
 | ||||
| 	/* 18.8.10 cellXfs CT_CellXfs ? */ | ||||
| 	if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts); | ||||
| 
 | ||||
| 	/* dxfs CT_Dxfs ? */ | ||||
| 	/* tableStyles CT_TableStyles ? */ | ||||
| 	/* colors CT_Colors ? */ | ||||
| 	/* extLst CT_ExtensionList ? */ | ||||
| 	/* 18.8.15 dxfs CT_Dxfs ? */ | ||||
| 	/* 18.8.42 tableStyles CT_TableStyles ? */ | ||||
| 	/* 18.8.11 colors CT_Colors ? */ | ||||
| 	/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 
 | ||||
| 	return styles; | ||||
| }; | ||||
| @ -5236,7 +5408,7 @@ function parse_BrtXF(data, length) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.50 Styles */ | ||||
| function parse_sty_bin(data, opts) { | ||||
| function parse_sty_bin(data, themes, opts) { | ||||
| 	var styles = {}; | ||||
| 	styles.NumberFmt = ([]); | ||||
| 	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; | ||||
| @ -9654,9 +9826,9 @@ function parse_ws(data, name, opts, rels, wb, themes, styles) { | ||||
| 	return parse_ws_xml((data), opts, rels, wb, themes, styles); | ||||
| } | ||||
| 
 | ||||
| function parse_sty(data, name, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_sty_bin((data), opts); | ||||
| 	return parse_sty_xml((data), opts); | ||||
| function parse_sty(data, name, themes, opts) { | ||||
| 	if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts); | ||||
| 	return parse_sty_xml((data), themes, opts); | ||||
| } | ||||
| 
 | ||||
| function parse_theme(data, name, opts) { | ||||
| @ -13279,9 +13451,9 @@ function parse_zip(zip, opts) { | ||||
| 		strs = []; | ||||
| 		if(dir.sst) strs=parse_sst(getzipdata(zip, dir.sst.replace(/^\//,'')), dir.sst, opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, dir.style.replace(/^\//,'')),dir.style, opts); | ||||
| 
 | ||||
| 		if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts); | ||||
| 
 | ||||
| 		if(dir.style) styles = parse_sty(getzipdata(zip, dir.style.replace(/^\//,'')),dir.style, themes, opts); | ||||
| 	} | ||||
| 
 | ||||
| 	var wb = parse_wb(getzipdata(zip, dir.workbooks[0].replace(/^\//,'')), dir.workbooks[0], opts); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user