forked from sheetjs/sheetjs
		
	HTML and CSV parsing
- blank cells are omitted or stubbed (fixes #770 h/t @doxma) - bare equals signs are interpred as strings - CSV / TSV determination based on frequency (fixes #732 h/t @nknapp) - HTML DOM Element and CSV tests - XLS do not leak XF and index (fixes #782 h/t @the-spyke) - cellText and cellNF apply to CSV (fixes #781 h/t @the-spyke)
This commit is contained in:
		
							parent
							
								
									f6981076ec
								
							
						
					
					
						commit
						2ea9c95839
					
				| @ -32,6 +32,8 @@ before_install: | ||||
|   - "npm install blanket" | ||||
|   - "npm install xlsjs" | ||||
|   - "npm install coveralls mocha-lcov-reporter" | ||||
| # note: jsdom 11.x expects node >= 6 but is missing engines.node | ||||
|   - "npm install jsdom@11.x" | ||||
| before_script: | ||||
|   - "make init" | ||||
|   - "cd test_files; make all; cd -" | ||||
|  | ||||
| @ -4,6 +4,10 @@ This log is intended to keep track of backwards-incompatible changes, including | ||||
| but not limited to API changes and file location changes.  Minor behavioral | ||||
| changes may not be included if they are not expected to break existing code. | ||||
| 
 | ||||
| ## Unreleased (2017-08-??) | ||||
| 
 | ||||
| * XLS cell ixfe/XF removed | ||||
| 
 | ||||
| ## 0.11.0 (2017-07-31) | ||||
| 
 | ||||
| * Strip `require` statements from minified version | ||||
|  | ||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							| @ -1385,7 +1385,7 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| | Option Name | Default | Description                                          | | ||||
| | :---------- | ------: | :--------------------------------------------------- | | ||||
| | type        |         | Input data encoding (see Input Type below)           | | ||||
| | raw         |         | If true, plaintext parsing will not parse values **  | | ||||
| | raw         | false   | If true, plaintext parsing will not parse values **  | | ||||
| | cellFormula | true    | Save formulae to the .f field                        | | ||||
| | cellHTML    | true    | Parse rich text and save HTML to the `.h` field      | | ||||
| | cellNF      | false   | Save number format string to the `.z` field          | | ||||
| @ -1473,8 +1473,8 @@ Plaintext format guessing follows the priority order: | ||||
| | XML    | starts with `<`                                                     | | ||||
| | RTF    | starts with `{\rt`                                                  | | ||||
| | DSV    | starts with `/sep=.$/`, separator is the specified character        | | ||||
| | CSV    | more unquoted `","` characters than `"\t"` chars in the first 1024  | | ||||
| | TSV    | one of the first 1024 characters is a tab char `"\t"`               | | ||||
| | CSV    | one of the first 1024 characters is a comma char `","`              | | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| - HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div` | ||||
| @ -1964,6 +1964,14 @@ writer proactively generates cells for formulae if values are unavailable. | ||||
| 
 | ||||
| Excel TXT uses tab as the delimiter and codepage 1200. | ||||
| 
 | ||||
| Notes: | ||||
| 
 | ||||
| - Like in Excel, files starting with `0x49 0x44 ("ID")` are treated as Symbolic | ||||
|   Link files.  Unlike Excel, if the file does not have a valid SYLK header, it | ||||
|   will be proactively reinterpreted as CSV.  There are some files with semicolon | ||||
|   delimiter that align with a valid SYLK file.  For the broadest compatibility, | ||||
|   all cells with the value of `ID` are automatically wrapped in double-quotes. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Other Workbook Formats | ||||
|  | ||||
| @ -512,6 +512,16 @@ var PRN = (function() { | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function guess_sep(str) { | ||||
| 		var cnt = [], instr = false, end = 0, cc = 0; | ||||
| 		for(;end < str.length;++end) { | ||||
| 			if((cc=str.charCodeAt(end)) == 0x22) instr = !instr; | ||||
| 			else if(!instr) cnt[cc] = (cnt[cc]||0)+1; | ||||
| 		} | ||||
| 		if(cnt[0x2C] > cnt[0x09]) return ","; | ||||
| 		return ","; | ||||
| 	} | ||||
| 
 | ||||
| 	function dsv_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ { | ||||
| 		var o = opts || {}; | ||||
| 		var sep = ""; | ||||
| @ -519,9 +529,8 @@ var PRN = (function() { | ||||
| 		var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/); | ||||
| 
 | ||||
| 		/* known sep */ | ||||
| 		if(str.substr(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.substr(6); } | ||||
| 		else if(str.substr(0,1024).indexOf("\t") == -1) sep = ","; else sep = "\t"; | ||||
| 		else sep = guess_sep(str.substr(0,1024)); | ||||
| 		var R = 0, C = 0, v = 0; | ||||
| 		var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0; | ||||
| 		str = str.replace(/\r\n/mg, "\n"); | ||||
| @ -529,24 +538,30 @@ var PRN = (function() { | ||||
| 		function finish_cell() { | ||||
| 			var s = str.slice(start, end); | ||||
| 			var cell = ({}/*:any*/); | ||||
| 			if(o.raw) { cell.t = 's'; cell.v = s; } | ||||
| 			else if(s.charCodeAt(0) == 0x3D) { cell.t = 'n'; cell.f = s.substr(1); } | ||||
| 			if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"'); | ||||
| 			if(s.length == 0) cell.t = 'z'; | ||||
| 			else if(o.raw) { cell.t = 's'; cell.v = s; } | ||||
| 			else if(s.charCodeAt(0) == 0x3D) { | ||||
| 				if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); } | ||||
| 				else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.substr(1); } | ||||
| 				else { cell.t = 's'; cell.v = s; } } | ||||
| 			else if(s == "TRUE") { cell.t = 'b'; cell.v = true; } | ||||
| 			else if(s == "FALSE") { cell.t = 'b'; cell.v = false; } | ||||
| 			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; cell.w = s; cell.v = v; } | ||||
| 			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; } | ||||
| 			else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) { | ||||
| 				cell.z = o.dateNF || SSF._table[14]; | ||||
| 				var k = 0; | ||||
| 				if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; } | ||||
| 				if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); } | ||||
| 				else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); } | ||||
| 				cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v); | ||||
| 				if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v); | ||||
| 				if(!o.cellNF) delete cell.z; | ||||
| 			} else { | ||||
| 				cell.t = 's'; | ||||
| 				if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"'); | ||||
| 				cell.v = s; | ||||
| 			} | ||||
| 			if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			if(cell.t == 'z'){} | ||||
| 			else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			else ws[encode_cell({c:C,r:R})] = cell; | ||||
| 			start = end+1; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| @ -579,7 +594,7 @@ var PRN = (function() { | ||||
| 			case 'array': str = cc2str(d); break; | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -40,3 +40,9 @@ function shift_formula_xlsx(f/*:string*/, range/*:string*/, cell/*:string*/)/*:s | ||||
| 	var delta = {r:c.r - s.r, c:c.c - s.c}; | ||||
| 	return shift_formula_str(f, delta); | ||||
| } | ||||
| 
 | ||||
| /* TODO: parse formula */ | ||||
| function fuzzyfmla(f/*:string*/)/*:boolean*/ { | ||||
| 	if(f.length == 1) return false; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @ -131,6 +131,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 		if(file_depth > 1) return; | ||||
| 		if(!cell_valid) return; | ||||
| 		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options); | ||||
| 		delete line.ixfe; delete line.XF; | ||||
| 		lastcell = cell; | ||||
| 		last_cell = encode_cell(cell); | ||||
| 		if(range.s) { | ||||
| @ -240,8 +241,11 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'FileSharing': break; //TODO
 | ||||
| 				case 'CodePage': | ||||
| 					/* overrides based on test cases */ | ||||
| 					if(val === 0x5212) val = 1200; | ||||
| 					else if(val === 0x8001) val = 1252; | ||||
| 					switch(val) { | ||||
| 						case 0x5212: val =  1200; break; | ||||
| 						case 0x8000: val = 10000; break; | ||||
| 						case 0x8001: val =  1252; break; | ||||
| 					} | ||||
| 					opts.codepage = val; | ||||
| 					set_cp(val); | ||||
| 					break; | ||||
|  | ||||
| @ -37,13 +37,19 @@ var HTML_ = (function() { | ||||
| 				if(range.e.c < C) range.e.c = C; | ||||
| 				if(opts.dense) { | ||||
| 					if(!ws[R]) ws[R] = []; | ||||
| 					if(opts.raw) ws[R][C] = {t:'s', v:m}; | ||||
| 					if(!m.length){} | ||||
| 					else if(opts.raw) ws[R][C] = {t:'s', v:m}; | ||||
| 					else if(m === 'TRUE') ws[R][C] = {t:'b', v:true}; | ||||
| 					else if(m === 'FALSE') ws[R][C] = {t:'b', v:false}; | ||||
| 					else if(!isNaN(fuzzynum(m))) ws[R][C] = {t:'n', v:fuzzynum(m)}; | ||||
| 					else ws[R][C] = {t:'s', v:m}; | ||||
| 				} else { | ||||
| 					var coord/*:string*/ = encode_cell({r:R, c:C}); | ||||
| 					/* TODO: value parsing */ | ||||
| 					if(opts.raw) ws[coord] = {t:'s', v:m}; | ||||
| 					if(!m.length){} | ||||
| 					else if(opts.raw) ws[coord] = {t:'s', v:m}; | ||||
| 					else if(m === 'TRUE') ws[coord] = {t:'b', v:true}; | ||||
| 					else if(m === 'FALSE') ws[coord] = {t:'b', v:false}; | ||||
| 					else if(!isNaN(fuzzynum(m))) ws[coord] = {t:'n', v:fuzzynum(m)}; | ||||
| 					else ws[coord] = {t:'s', v:m}; | ||||
| 				} | ||||
| @ -126,7 +132,7 @@ function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 		var row = rows[R]; | ||||
| 		var elts = row.children; | ||||
| 		for(_C = C = 0; _C < elts.length; ++_C) { | ||||
| 			var elt = elts[_C], v = elts[_C].innerText || elts[_C].textContent; | ||||
| 			var elt = elts[_C], v = elts[_C].innerText || elts[_C].textContent || ""; | ||||
| 			for(midx = 0; midx < merges.length; ++midx) { | ||||
| 				var m = merges[midx]; | ||||
| 				if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; } | ||||
| @ -135,8 +141,11 @@ function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); | ||||
| 			var o/*:Cell*/ = {t:'s', v:v}; | ||||
| 			if(v != null && v.length) { | ||||
| 				if(opts.raw) o = {t:'s', v:v}; | ||||
| 			if(v != null) { | ||||
| 				if(v.length == 0) o.t = 'z'; | ||||
| 				else if(opts.raw){} | ||||
| 				else if(v === 'TRUE') o = {t:'b', v:true}; | ||||
| 				else if(v === 'FALSE') o = {t:'b', v:false}; | ||||
| 				else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; | ||||
| 				else if(!isNaN(fuzzydate(v).getDate())) { | ||||
| 					o = ({t:'d', v:parseDate(v)}/*:any*/); | ||||
|  | ||||
| @ -5,7 +5,7 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| | Option Name | Default | Description                                          | | ||||
| | :---------- | ------: | :--------------------------------------------------- | | ||||
| | type        |         | Input data encoding (see Input Type below)           | | ||||
| | raw         |         | If true, plaintext parsing will not parse values **  | | ||||
| | raw         | false   | If true, plaintext parsing will not parse values **  | | ||||
| | cellFormula | true    | Save formulae to the .f field                        | | ||||
| | cellHTML    | true    | Parse rich text and save HTML to the `.h` field      | | ||||
| | cellNF      | false   | Save number format string to the `.z` field          | | ||||
| @ -93,8 +93,8 @@ Plaintext format guessing follows the priority order: | ||||
| | XML    | starts with `<`                                                     | | ||||
| | RTF    | starts with `{\rt`                                                  | | ||||
| | DSV    | starts with `/sep=.$/`, separator is the specified character        | | ||||
| | CSV    | more unquoted `","` characters than `"\t"` chars in the first 1024  | | ||||
| | TSV    | one of the first 1024 characters is a tab char `"\t"`               | | ||||
| | CSV    | one of the first 1024 characters is a comma char `","`              | | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| - HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div` | ||||
|  | ||||
| @ -113,6 +113,14 @@ writer proactively generates cells for formulae if values are unavailable. | ||||
| 
 | ||||
| Excel TXT uses tab as the delimiter and codepage 1200. | ||||
| 
 | ||||
| Notes: | ||||
| 
 | ||||
| - Like in Excel, files starting with `0x49 0x44 ("ID")` are treated as Symbolic | ||||
|   Link files.  Unlike Excel, if the file does not have a valid SYLK header, it | ||||
|   will be proactively reinterpreted as CSV.  There are some files with semicolon | ||||
|   delimiter that align with a valid SYLK file.  For the broadest compatibility, | ||||
|   all cells with the value of `ID` are automatically wrapped in double-quotes. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Other Workbook Formats | ||||
|  | ||||
| @ -1274,7 +1274,7 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| | Option Name | Default | Description                                          | | ||||
| | :---------- | ------: | :--------------------------------------------------- | | ||||
| | type        |         | Input data encoding (see Input Type below)           | | ||||
| | raw         |         | If true, plaintext parsing will not parse values **  | | ||||
| | raw         | false   | If true, plaintext parsing will not parse values **  | | ||||
| | cellFormula | true    | Save formulae to the .f field                        | | ||||
| | cellHTML    | true    | Parse rich text and save HTML to the `.h` field      | | ||||
| | cellNF      | false   | Save number format string to the `.z` field          | | ||||
| @ -1360,8 +1360,8 @@ Plaintext format guessing follows the priority order: | ||||
| | XML    | starts with `<`                                                     | | ||||
| | RTF    | starts with `{\rt`                                                  | | ||||
| | DSV    | starts with `/sep=.$/`, separator is the specified character        | | ||||
| | CSV    | more unquoted `","` characters than `"\t"` chars in the first 1024  | | ||||
| | TSV    | one of the first 1024 characters is a tab char `"\t"`               | | ||||
| | CSV    | one of the first 1024 characters is a comma char `","`              | | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| - HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div` | ||||
| @ -1809,6 +1809,14 @@ writer proactively generates cells for formulae if values are unavailable. | ||||
| 
 | ||||
| Excel TXT uses tab as the delimiter and codepage 1200. | ||||
| 
 | ||||
| Notes: | ||||
| 
 | ||||
| - Like in Excel, files starting with `0x49 0x44 ("ID")` are treated as Symbolic | ||||
|   Link files.  Unlike Excel, if the file does not have a valid SYLK header, it | ||||
|   will be proactively reinterpreted as CSV.  There are some files with semicolon | ||||
|   delimiter that align with a valid SYLK file.  For the broadest compatibility, | ||||
|   all cells with the value of `ID` are automatically wrapped in double-quotes. | ||||
| 
 | ||||
| 
 | ||||
| ### Other Workbook Formats | ||||
| 
 | ||||
|  | ||||
| @ -31,6 +31,7 @@ | ||||
| 		"@sheetjs/uglify-js":"~2.7.3", | ||||
| 		"@types/node":"^8.0.7", | ||||
| 		"@types/commander":"^2.9.0", | ||||
| 		"jsdom": "~11.1.0", | ||||
| 		"dtslint": "^0.1.2", | ||||
| 		"typescript": "2.2.0" | ||||
| 	}, | ||||
|  | ||||
							
								
								
									
										93
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										93
									
								
								test.js
									
									
									
									
									
								
							| @ -1723,6 +1723,39 @@ describe('json output', function() { | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| var codes = [["あ 1", "\u00E3\u0081\u0082 1"]] | ||||
| var plaintext_val = [ | ||||
| 	["A1", 'n', -0.08,  "-0.08"], | ||||
| 	["B1", 'n', 4001,   "4,001"], | ||||
| 	["C1", 's', "あ 1",  "あ 1"], | ||||
| 	["A2", 'n', 41.08, "$41.08"], | ||||
| 	["B2", 'n', 0.11,     "11%"], | ||||
| 	["B3", 'b', true,    "TRUE"], | ||||
| 	["C3", 'b', false,  "FALSE"], | ||||
| 	["A3"]]; | ||||
| function plaintext_test(wb, raw, sn) { | ||||
| 	var sheet = wb.Sheets[sn || wb.SheetNames[0]]; | ||||
| 	plaintext_val.forEach(function(x) { | ||||
| 		var cell = get_cell(sheet, x[0]); | ||||
| 		if(x.length == 1) { if(cell) { assert.equal(cell.t, 'z'); assert(!cell.v); } return; } | ||||
| 		assert.equal(cell.v, x[2+!!raw]); assert.equal(cell.t, raw ? 's' : x[1]); | ||||
| 	}); | ||||
| } | ||||
| function make_html_str(idx) { return ["<table>", | ||||
| 	"<tr><td>-0.08</td><td>4,001</td><td>", codes[0][idx], "</td></tr>", | ||||
| 	"<tr><td>$41.08</td><td>11%</td></tr>", | ||||
| 	"<tr><td></td><td>TRUE</td><td>FALSE</td></tr>", | ||||
| "</table>" ].join(""); } | ||||
| function make_csv_str(idx) { return [ '\u00EF\u00BB\u00BF' + | ||||
| 	'-0.08,"4,001",' + codes[0][idx] + '', | ||||
| 	'$41.08,11%', | ||||
| 	',TRUE,FALSE' | ||||
| ].join("\n"); } | ||||
| var html_bstr = make_html_str(1), html_str = make_html_str(0); | ||||
| var csv_bstr = make_csv_str(1); | ||||
| 
 | ||||
| 
 | ||||
| describe('csv', function() { | ||||
| 	describe('input', function(){ | ||||
| 		var b = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n"; | ||||
| @ -1769,6 +1802,17 @@ describe('csv', function() { | ||||
| 			assert.equal(cell.v.getMonth(), 2); | ||||
| 			assert.equal(cell.w, "2/3/14"); | ||||
| 		}); | ||||
| 		it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); }); | ||||
| 		it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_bstr, {type:"binary", raw:true}), true); }); | ||||
| 		it('should handle formulae', function() { | ||||
| 			var bb = '=,=1+1,="100"'; | ||||
| 			var sheet = X.read(bb, {type:"binary"}).Sheets.Sheet1; | ||||
| 			assert.equal(get_cell(sheet, "A1").t, 's'); | ||||
| 			assert.equal(get_cell(sheet, "A1").v, '='); | ||||
| 			assert.equal(get_cell(sheet, "B1").f, '1+1'); | ||||
| 			assert.equal(get_cell(sheet, "C1").t, 's'); | ||||
| 			assert.equal(get_cell(sheet, "C1").v, '100'); | ||||
| 		}); | ||||
| 	}); | ||||
| 	describe('output', function(){ | ||||
| 		var data, ws; | ||||
| @ -1845,37 +1889,26 @@ describe('csv', function() { | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| var JSDOM = null; | ||||
| var domtest = browser || (function(){try{return !!(JSDOM=require('jsdom').JSDOM);}catch(e){return 0;}})(); | ||||
| 
 | ||||
| function get_dom_element(html) { | ||||
| 	if(browser) { | ||||
| 		var domelt = document.createElement('div'); | ||||
| 		domelt.innerHTML = html; | ||||
| 		return domelt; | ||||
| 	} | ||||
| 	return new JSDOM(html).window.document.body.children[0]; | ||||
| } | ||||
| 
 | ||||
| describe('HTML', function() { | ||||
| 	describe('input', function(){ | ||||
| 		var b = "<table><tr><td>-0.08</td><td>4,001</td><td>\u00e3\u0081\u0082 1</td></tr><tr><td>$41.08</td><td>11%</td></tr></table>"; | ||||
| 		it('should generate numbers by default', function() { | ||||
| 			var sheet = X.read(b, {type:"binary"}).Sheets.Sheet1; | ||||
| 			var cell = get_cell(sheet, "A1"); | ||||
| 			assert.equal(cell.v, -0.08); | ||||
| 			assert.equal(cell.t, 'n'); | ||||
| 			cell = get_cell(sheet, "B1"); | ||||
| 			assert.equal(cell.v, 4001); | ||||
| 			cell = get_cell(sheet, "C1"); | ||||
| 			assert.equal(cell.v, "あ 1"); | ||||
| 			cell = get_cell(sheet, "A2"); | ||||
| 			assert.equal(cell.v, 41.08); | ||||
| 			cell = get_cell(sheet, "B2"); | ||||
| 			assert.equal(cell.v, .11); | ||||
| 		}); | ||||
| 		it('should generate strings if raw option is passed', function() { | ||||
| 			var sheet = X.read(b, {type:"binary", raw:true}).Sheets.Sheet1; | ||||
| 			var cell = get_cell(sheet, "A1"); | ||||
| 			assert.equal(cell.v, "-0.08"); | ||||
| 			assert.equal(cell.t, 's'); | ||||
| 			cell = get_cell(sheet, "B1"); | ||||
| 			assert.equal(cell.v, "4,001"); | ||||
| 			cell = get_cell(sheet, "C1"); | ||||
| 			assert.equal(cell.v, "あ 1"); | ||||
| 			cell = get_cell(sheet, "A2"); | ||||
| 			assert.equal(cell.v, "$41.08"); | ||||
| 			cell = get_cell(sheet, "B2"); | ||||
| 			assert.equal(cell.v, "11%"); | ||||
| 		}); | ||||
| 	describe('input string', function(){ | ||||
| 		it('should interpret values by default', function() { plaintext_test(X.read(html_bstr, {type:"binary"}), false); }); | ||||
| 		it('should generate strings if raw option is passed', function() { plaintext_test(X.read(html_bstr, {type:"binary", raw:true}), true); }); | ||||
| 	}); | ||||
| 	(domtest ? describe : describe.skip)('input DOM', function() { | ||||
| 		it('should interpret values by default', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str)), false); }); | ||||
| 		it('should generate strings if raw option is passed', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str), {raw:true}), true); }); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
|  | ||||
| @ -1723,6 +1723,39 @@ describe('json output', function() { | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| var codes = [["あ 1", "\u00E3\u0081\u0082 1"]] | ||||
| var plaintext_val = [ | ||||
| 	["A1", 'n', -0.08,  "-0.08"], | ||||
| 	["B1", 'n', 4001,   "4,001"], | ||||
| 	["C1", 's', "あ 1",  "あ 1"], | ||||
| 	["A2", 'n', 41.08, "$41.08"], | ||||
| 	["B2", 'n', 0.11,     "11%"], | ||||
| 	["B3", 'b', true,    "TRUE"], | ||||
| 	["C3", 'b', false,  "FALSE"], | ||||
| 	["A3"]]; | ||||
| function plaintext_test(wb, raw, sn) { | ||||
| 	var sheet = wb.Sheets[sn || wb.SheetNames[0]]; | ||||
| 	plaintext_val.forEach(function(x) { | ||||
| 		var cell = get_cell(sheet, x[0]); | ||||
| 		if(x.length == 1) { if(cell) { assert.equal(cell.t, 'z'); assert(!cell.v); } return; } | ||||
| 		assert.equal(cell.v, x[2+!!raw]); assert.equal(cell.t, raw ? 's' : x[1]); | ||||
| 	}); | ||||
| } | ||||
| function make_html_str(idx) { return ["<table>", | ||||
| 	"<tr><td>-0.08</td><td>4,001</td><td>", codes[0][idx], "</td></tr>", | ||||
| 	"<tr><td>$41.08</td><td>11%</td></tr>", | ||||
| 	"<tr><td></td><td>TRUE</td><td>FALSE</td></tr>", | ||||
| "</table>" ].join(""); } | ||||
| function make_csv_str(idx) { return [ '\u00EF\u00BB\u00BF' + | ||||
| 	'-0.08,"4,001",' + codes[0][idx] + '', | ||||
| 	'$41.08,11%', | ||||
| 	',TRUE,FALSE' | ||||
| ].join("\n"); } | ||||
| var html_bstr = make_html_str(1), html_str = make_html_str(0); | ||||
| var csv_bstr = make_csv_str(1); | ||||
| 
 | ||||
| 
 | ||||
| describe('csv', function() { | ||||
| 	describe('input', function(){ | ||||
| 		var b = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n"; | ||||
| @ -1769,6 +1802,17 @@ describe('csv', function() { | ||||
| 			assert.equal(cell.v.getMonth(), 2); | ||||
| 			assert.equal(cell.w, "2/3/14"); | ||||
| 		}); | ||||
| 		it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); }); | ||||
| 		it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_bstr, {type:"binary", raw:true}), true); }); | ||||
| 		it('should handle formulae', function() { | ||||
| 			var bb = '=,=1+1,="100"'; | ||||
| 			var sheet = X.read(bb, {type:"binary"}).Sheets.Sheet1; | ||||
| 			assert.equal(get_cell(sheet, "A1").t, 's'); | ||||
| 			assert.equal(get_cell(sheet, "A1").v, '='); | ||||
| 			assert.equal(get_cell(sheet, "B1").f, '1+1'); | ||||
| 			assert.equal(get_cell(sheet, "C1").t, 's'); | ||||
| 			assert.equal(get_cell(sheet, "C1").v, '100'); | ||||
| 		}); | ||||
| 	}); | ||||
| 	describe('output', function(){ | ||||
| 		var data, ws; | ||||
| @ -1845,37 +1889,26 @@ describe('csv', function() { | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| var JSDOM = null; | ||||
| var domtest = browser || (function(){try{return !!(JSDOM=require('jsdom').JSDOM);}catch(e){return 0;}})(); | ||||
| 
 | ||||
| function get_dom_element(html) { | ||||
| 	if(browser) { | ||||
| 		var domelt = document.createElement('div'); | ||||
| 		domelt.innerHTML = html; | ||||
| 		return domelt; | ||||
| 	} | ||||
| 	return new JSDOM(html).window.document.body.children[0]; | ||||
| } | ||||
| 
 | ||||
| describe('HTML', function() { | ||||
| 	describe('input', function(){ | ||||
| 		var b = "<table><tr><td>-0.08</td><td>4,001</td><td>\u00e3\u0081\u0082 1</td></tr><tr><td>$41.08</td><td>11%</td></tr></table>"; | ||||
| 		it('should generate numbers by default', function() { | ||||
| 			var sheet = X.read(b, {type:"binary"}).Sheets.Sheet1; | ||||
| 			var cell = get_cell(sheet, "A1"); | ||||
| 			assert.equal(cell.v, -0.08); | ||||
| 			assert.equal(cell.t, 'n'); | ||||
| 			cell = get_cell(sheet, "B1"); | ||||
| 			assert.equal(cell.v, 4001); | ||||
| 			cell = get_cell(sheet, "C1"); | ||||
| 			assert.equal(cell.v, "あ 1"); | ||||
| 			cell = get_cell(sheet, "A2"); | ||||
| 			assert.equal(cell.v, 41.08); | ||||
| 			cell = get_cell(sheet, "B2"); | ||||
| 			assert.equal(cell.v, .11); | ||||
| 		}); | ||||
| 		it('should generate strings if raw option is passed', function() { | ||||
| 			var sheet = X.read(b, {type:"binary", raw:true}).Sheets.Sheet1; | ||||
| 			var cell = get_cell(sheet, "A1"); | ||||
| 			assert.equal(cell.v, "-0.08"); | ||||
| 			assert.equal(cell.t, 's'); | ||||
| 			cell = get_cell(sheet, "B1"); | ||||
| 			assert.equal(cell.v, "4,001"); | ||||
| 			cell = get_cell(sheet, "C1"); | ||||
| 			assert.equal(cell.v, "あ 1"); | ||||
| 			cell = get_cell(sheet, "A2"); | ||||
| 			assert.equal(cell.v, "$41.08"); | ||||
| 			cell = get_cell(sheet, "B2"); | ||||
| 			assert.equal(cell.v, "11%"); | ||||
| 		}); | ||||
| 	describe('input string', function(){ | ||||
| 		it('should interpret values by default', function() { plaintext_test(X.read(html_bstr, {type:"binary"}), false); }); | ||||
| 		it('should generate strings if raw option is passed', function() { plaintext_test(X.read(html_bstr, {type:"binary", raw:true}), true); }); | ||||
| 	}); | ||||
| 	(domtest ? describe : describe.skip)('input DOM', function() { | ||||
| 		it('should interpret values by default', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str)), false); }); | ||||
| 		it('should generate strings if raw option is passed', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str), {raw:true}), true); }); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
|  | ||||
| @ -80,7 +80,7 @@ ws['!rows'] = wsrows; | ||||
| 
 | ||||
| /* TEST: hyperlink note: Excel does not automatically style hyperlinks */ | ||||
| (<XLSX.CellObject>ws['A3']).l = { Target: "http://sheetjs.com", Tooltip: "Visit us <SheetJS.com!>" }; | ||||
| XLSX.utils.cell_set_hyperlink(ws['A3'], "http://sheetjs.com", "Visit us <SheetJS.com!>" ); | ||||
| XLSX.utils.cell_set_hyperlink(ws['A3'], "http://sheetjs.com", "Visit us <SheetJS.com!>"); | ||||
| 
 | ||||
| /* TEST: built-in format */ | ||||
| (<XLSX.CellObject>ws['B1']).z = "0%"; // Format Code 9
 | ||||
|  | ||||
							
								
								
									
										66
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										66
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -5786,6 +5786,16 @@ var PRN = (function() { | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function guess_sep(str) { | ||||
| 		var cnt = [], instr = false, end = 0, cc = 0; | ||||
| 		for(;end < str.length;++end) { | ||||
| 			if((cc=str.charCodeAt(end)) == 0x22) instr = !instr; | ||||
| 			else if(!instr) cnt[cc] = (cnt[cc]||0)+1; | ||||
| 		} | ||||
| 		if(cnt[0x2C] > cnt[0x09]) return ","; | ||||
| 		return ","; | ||||
| 	} | ||||
| 
 | ||||
| 	function dsv_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ { | ||||
| 		var o = opts || {}; | ||||
| 		var sep = ""; | ||||
| @ -5793,9 +5803,8 @@ var PRN = (function() { | ||||
| 		var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/); | ||||
| 
 | ||||
| 		/* known sep */ | ||||
| 		if(str.substr(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.substr(6); } | ||||
| 		else if(str.substr(0,1024).indexOf("\t") == -1) sep = ","; else sep = "\t"; | ||||
| 		else sep = guess_sep(str.substr(0,1024)); | ||||
| 		var R = 0, C = 0, v = 0; | ||||
| 		var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0; | ||||
| 		str = str.replace(/\r\n/mg, "\n"); | ||||
| @ -5803,24 +5812,30 @@ var PRN = (function() { | ||||
| 		function finish_cell() { | ||||
| 			var s = str.slice(start, end); | ||||
| 			var cell = ({}/*:any*/); | ||||
| 			if(o.raw) { cell.t = 's'; cell.v = s; } | ||||
| 			else if(s.charCodeAt(0) == 0x3D) { cell.t = 'n'; cell.f = s.substr(1); } | ||||
| 			if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"'); | ||||
| 			if(s.length == 0) cell.t = 'z'; | ||||
| 			else if(o.raw) { cell.t = 's'; cell.v = s; } | ||||
| 			else if(s.charCodeAt(0) == 0x3D) { | ||||
| 				if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); } | ||||
| 				else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.substr(1); } | ||||
| 				else { cell.t = 's'; cell.v = s; } } | ||||
| 			else if(s == "TRUE") { cell.t = 'b'; cell.v = true; } | ||||
| 			else if(s == "FALSE") { cell.t = 'b'; cell.v = false; } | ||||
| 			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; cell.w = s; cell.v = v; } | ||||
| 			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; } | ||||
| 			else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) { | ||||
| 				cell.z = o.dateNF || SSF._table[14]; | ||||
| 				var k = 0; | ||||
| 				if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; } | ||||
| 				if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); } | ||||
| 				else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); } | ||||
| 				cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v); | ||||
| 				if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v); | ||||
| 				if(!o.cellNF) delete cell.z; | ||||
| 			} else { | ||||
| 				cell.t = 's'; | ||||
| 				if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"'); | ||||
| 				cell.v = s; | ||||
| 			} | ||||
| 			if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			if(cell.t == 'z'){} | ||||
| 			else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			else ws[encode_cell({c:C,r:R})] = cell; | ||||
| 			start = end+1; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| @ -5853,7 +5868,7 @@ var PRN = (function() { | ||||
| 			case 'array': str = cc2str(d); break; | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| 
 | ||||
| @ -8466,6 +8481,12 @@ function shift_formula_xlsx(f/*:string*/, range/*:string*/, cell/*:string*/)/*:s | ||||
| 	var delta = {r:c.r - s.r, c:c.c - s.c}; | ||||
| 	return shift_formula_str(f, delta); | ||||
| } | ||||
| 
 | ||||
| /* TODO: parse formula */ | ||||
| function fuzzyfmla(f/*:string*/)/*:boolean*/ { | ||||
| 	if(f.length == 1) return false; | ||||
| 	return true; | ||||
| } | ||||
| /* --- formula references point to MS-XLS --- */ | ||||
| /* Small helpers */ | ||||
| function parseread(l) { return function(blob, length) { blob.l+=l; return; }; } | ||||
| @ -14285,6 +14306,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 		if(file_depth > 1) return; | ||||
| 		if(!cell_valid) return; | ||||
| 		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options); | ||||
| 		delete line.ixfe; delete line.XF; | ||||
| 		lastcell = cell; | ||||
| 		last_cell = encode_cell(cell); | ||||
| 		if(range.s) { | ||||
| @ -14394,8 +14416,11 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'FileSharing': break; //TODO
 | ||||
| 				case 'CodePage': | ||||
| 					/* overrides based on test cases */ | ||||
| 					if(val === 0x5212) val = 1200; | ||||
| 					else if(val === 0x8001) val = 1252; | ||||
| 					switch(val) { | ||||
| 						case 0x5212: val =  1200; break; | ||||
| 						case 0x8000: val = 10000; break; | ||||
| 						case 0x8001: val =  1252; break; | ||||
| 					} | ||||
| 					opts.codepage = val; | ||||
| 					set_cp(val); | ||||
| 					break; | ||||
| @ -16412,13 +16437,19 @@ var HTML_ = (function() { | ||||
| 				if(range.e.c < C) range.e.c = C; | ||||
| 				if(opts.dense) { | ||||
| 					if(!ws[R]) ws[R] = []; | ||||
| 					if(opts.raw) ws[R][C] = {t:'s', v:m}; | ||||
| 					if(!m.length){} | ||||
| 					else if(opts.raw) ws[R][C] = {t:'s', v:m}; | ||||
| 					else if(m === 'TRUE') ws[R][C] = {t:'b', v:true}; | ||||
| 					else if(m === 'FALSE') ws[R][C] = {t:'b', v:false}; | ||||
| 					else if(!isNaN(fuzzynum(m))) ws[R][C] = {t:'n', v:fuzzynum(m)}; | ||||
| 					else ws[R][C] = {t:'s', v:m}; | ||||
| 				} else { | ||||
| 					var coord/*:string*/ = encode_cell({r:R, c:C}); | ||||
| 					/* TODO: value parsing */ | ||||
| 					if(opts.raw) ws[coord] = {t:'s', v:m}; | ||||
| 					if(!m.length){} | ||||
| 					else if(opts.raw) ws[coord] = {t:'s', v:m}; | ||||
| 					else if(m === 'TRUE') ws[coord] = {t:'b', v:true}; | ||||
| 					else if(m === 'FALSE') ws[coord] = {t:'b', v:false}; | ||||
| 					else if(!isNaN(fuzzynum(m))) ws[coord] = {t:'n', v:fuzzynum(m)}; | ||||
| 					else ws[coord] = {t:'s', v:m}; | ||||
| 				} | ||||
| @ -16501,7 +16532,7 @@ function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 		var row = rows[R]; | ||||
| 		var elts = row.children; | ||||
| 		for(_C = C = 0; _C < elts.length; ++_C) { | ||||
| 			var elt = elts[_C], v = elts[_C].innerText || elts[_C].textContent; | ||||
| 			var elt = elts[_C], v = elts[_C].innerText || elts[_C].textContent || ""; | ||||
| 			for(midx = 0; midx < merges.length; ++midx) { | ||||
| 				var m = merges[midx]; | ||||
| 				if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; } | ||||
| @ -16510,8 +16541,11 @@ function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); | ||||
| 			var o/*:Cell*/ = {t:'s', v:v}; | ||||
| 			if(v != null && v.length) { | ||||
| 				if(opts.raw) o = {t:'s', v:v}; | ||||
| 			if(v != null) { | ||||
| 				if(v.length == 0) o.t = 'z'; | ||||
| 				else if(opts.raw){} | ||||
| 				else if(v === 'TRUE') o = {t:'b', v:true}; | ||||
| 				else if(v === 'FALSE') o = {t:'b', v:false}; | ||||
| 				else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; | ||||
| 				else if(!isNaN(fuzzydate(v).getDate())) { | ||||
| 					o = ({t:'d', v:parseDate(v)}/*:any*/); | ||||
|  | ||||
							
								
								
									
										66
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										66
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -5712,6 +5712,16 @@ var PRN = (function() { | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function guess_sep(str) { | ||||
| 		var cnt = [], instr = false, end = 0, cc = 0; | ||||
| 		for(;end < str.length;++end) { | ||||
| 			if((cc=str.charCodeAt(end)) == 0x22) instr = !instr; | ||||
| 			else if(!instr) cnt[cc] = (cnt[cc]||0)+1; | ||||
| 		} | ||||
| 		if(cnt[0x2C] > cnt[0x09]) return ","; | ||||
| 		return ","; | ||||
| 	} | ||||
| 
 | ||||
| 	function dsv_to_sheet_str(str, opts) { | ||||
| 		var o = opts || {}; | ||||
| 		var sep = ""; | ||||
| @ -5719,9 +5729,8 @@ var PRN = (function() { | ||||
| 		var ws = o.dense ? ([]) : ({}); | ||||
| 		var range = ({s: {c:0, r:0}, e: {c:0, r:0}}); | ||||
| 
 | ||||
| 		/* known sep */ | ||||
| 		if(str.substr(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.substr(6); } | ||||
| 		else if(str.substr(0,1024).indexOf("\t") == -1) sep = ","; else sep = "\t"; | ||||
| 		else sep = guess_sep(str.substr(0,1024)); | ||||
| 		var R = 0, C = 0, v = 0; | ||||
| 		var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0; | ||||
| 		str = str.replace(/\r\n/mg, "\n"); | ||||
| @ -5729,24 +5738,30 @@ var PRN = (function() { | ||||
| 		function finish_cell() { | ||||
| 			var s = str.slice(start, end); | ||||
| 			var cell = ({}); | ||||
| 			if(o.raw) { cell.t = 's'; cell.v = s; } | ||||
| 			else if(s.charCodeAt(0) == 0x3D) { cell.t = 'n'; cell.f = s.substr(1); } | ||||
| 			if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"'); | ||||
| 			if(s.length == 0) cell.t = 'z'; | ||||
| 			else if(o.raw) { cell.t = 's'; cell.v = s; } | ||||
| 			else if(s.charCodeAt(0) == 0x3D) { | ||||
| 				if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); } | ||||
| 				else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.substr(1); } | ||||
| 				else { cell.t = 's'; cell.v = s; } } | ||||
| 			else if(s == "TRUE") { cell.t = 'b'; cell.v = true; } | ||||
| 			else if(s == "FALSE") { cell.t = 'b'; cell.v = false; } | ||||
| 			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; cell.w = s; cell.v = v; } | ||||
| 			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; } | ||||
| 			else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) { | ||||
| 				cell.z = o.dateNF || SSF._table[14]; | ||||
| 				var k = 0; | ||||
| 				if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; } | ||||
| 				if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); } | ||||
| 				else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); } | ||||
| 				cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v); | ||||
| 				if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v); | ||||
| 				if(!o.cellNF) delete cell.z; | ||||
| 			} else { | ||||
| 				cell.t = 's'; | ||||
| 				if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"'); | ||||
| 				cell.v = s; | ||||
| 			} | ||||
| 			if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			if(cell.t == 'z'){} | ||||
| 			else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; } | ||||
| 			else ws[encode_cell({c:C,r:R})] = cell; | ||||
| 			start = end+1; | ||||
| 			if(range.e.c < C) range.e.c = C; | ||||
| @ -5779,7 +5794,7 @@ var PRN = (function() { | ||||
| 			case 'array': str = cc2str(d); break; | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| 
 | ||||
| @ -8389,6 +8404,12 @@ function shift_formula_xlsx(f, range, cell) { | ||||
| 	var delta = {r:c.r - s.r, c:c.c - s.c}; | ||||
| 	return shift_formula_str(f, delta); | ||||
| } | ||||
| 
 | ||||
| /* TODO: parse formula */ | ||||
| function fuzzyfmla(f) { | ||||
| 	if(f.length == 1) return false; | ||||
| 	return true; | ||||
| } | ||||
| /* --- formula references point to MS-XLS --- */ | ||||
| /* Small helpers */ | ||||
| function parseread(l) { return function(blob, length) { blob.l+=l; return; }; } | ||||
| @ -14200,6 +14221,7 @@ function parse_workbook(blob, options) { | ||||
| 		if(file_depth > 1) return; | ||||
| 		if(!cell_valid) return; | ||||
| 		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options); | ||||
| 		delete line.ixfe; delete line.XF; | ||||
| 		lastcell = cell; | ||||
| 		last_cell = encode_cell(cell); | ||||
| 		if(range.s) { | ||||
| @ -14308,8 +14330,11 @@ wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 				case 'FileSharing': break; //TODO
 | ||||
| 				case 'CodePage': | ||||
| 					/* overrides based on test cases */ | ||||
| 					if(val === 0x5212) val = 1200; | ||||
| 					else if(val === 0x8001) val = 1252; | ||||
| 					switch(val) { | ||||
| 						case 0x5212: val =  1200; break; | ||||
| 						case 0x8000: val = 10000; break; | ||||
| 						case 0x8001: val =  1252; break; | ||||
| 					} | ||||
| 					opts.codepage = val; | ||||
| 					set_cp(val); | ||||
| 					break; | ||||
| @ -16326,13 +16351,19 @@ var HTML_ = (function() { | ||||
| 				if(range.e.c < C) range.e.c = C; | ||||
| 				if(opts.dense) { | ||||
| 					if(!ws[R]) ws[R] = []; | ||||
| 					if(opts.raw) ws[R][C] = {t:'s', v:m}; | ||||
| 					if(!m.length){} | ||||
| 					else if(opts.raw) ws[R][C] = {t:'s', v:m}; | ||||
| 					else if(m === 'TRUE') ws[R][C] = {t:'b', v:true}; | ||||
| 					else if(m === 'FALSE') ws[R][C] = {t:'b', v:false}; | ||||
| 					else if(!isNaN(fuzzynum(m))) ws[R][C] = {t:'n', v:fuzzynum(m)}; | ||||
| 					else ws[R][C] = {t:'s', v:m}; | ||||
| 				} else { | ||||
| 					var coord = encode_cell({r:R, c:C}); | ||||
| 					/* TODO: value parsing */ | ||||
| 					if(opts.raw) ws[coord] = {t:'s', v:m}; | ||||
| 					if(!m.length){} | ||||
| 					else if(opts.raw) ws[coord] = {t:'s', v:m}; | ||||
| 					else if(m === 'TRUE') ws[coord] = {t:'b', v:true}; | ||||
| 					else if(m === 'FALSE') ws[coord] = {t:'b', v:false}; | ||||
| 					else if(!isNaN(fuzzynum(m))) ws[coord] = {t:'n', v:fuzzynum(m)}; | ||||
| 					else ws[coord] = {t:'s', v:m}; | ||||
| 				} | ||||
| @ -16415,7 +16446,7 @@ function parse_dom_table(table, _opts) { | ||||
| 		var row = rows[R]; | ||||
| 		var elts = row.children; | ||||
| 		for(_C = C = 0; _C < elts.length; ++_C) { | ||||
| 			var elt = elts[_C], v = elts[_C].innerText || elts[_C].textContent; | ||||
| 			var elt = elts[_C], v = elts[_C].innerText || elts[_C].textContent || ""; | ||||
| 			for(midx = 0; midx < merges.length; ++midx) { | ||||
| 				var m = merges[midx]; | ||||
| 				if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; } | ||||
| @ -16424,8 +16455,11 @@ function parse_dom_table(table, _opts) { | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); | ||||
| 			var o = {t:'s', v:v}; | ||||
| 			if(v != null && v.length) { | ||||
| 				if(opts.raw) o = {t:'s', v:v}; | ||||
| 			if(v != null) { | ||||
| 				if(v.length == 0) o.t = 'z'; | ||||
| 				else if(opts.raw){} | ||||
| 				else if(v === 'TRUE') o = {t:'b', v:true}; | ||||
| 				else if(v === 'FALSE') o = {t:'b', v:false}; | ||||
| 				else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; | ||||
| 				else if(!isNaN(fuzzydate(v).getDate())) { | ||||
| 					o = ({t:'d', v:parseDate(v)}); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user