From 6853c99ce53cfb3a9409563e2f75d85904a9c4e3 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Wed, 19 Apr 2017 23:24:48 -0400 Subject: [PATCH] rich text HTML + preview --- README.md | 13 +++++++++---- bits/42_sstxml.js | 36 +++++++++++++++++++++++++++------- bits/48_stybin.js | 5 ++++- bits/90_utils.js | 6 +++--- docbits/00_intro.md | 13 +++++++++---- index.html | 47 ++++++++++++++++++++++++++++++++++++--------- test.js | 2 +- xlsx.flow.js | 47 ++++++++++++++++++++++++++++++++++----------- xlsx.js | 47 ++++++++++++++++++++++++++++++++++----------- 9 files changed, 165 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 9e225d0..acfd01a 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,23 @@ -# xlsx +# [:green_book: SheetJS js-xlsx](http://sheetjs.com) Parser and writer for various spreadsheet formats. Pure-JS cleanroom implementation from official specifications, related documents, and test files. Emphasis on parsing and writing robustness, cross-format feature compatibility with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. -[**In-Browser Demo**](http://oss.sheetjs.com/js-xlsx) +This is the community version. We also offer a pro version with performance +enhancements and additional features by request. -[**Source Code**](http://git.io/xlsx) +[**Pro Version**](http://sheetjs.com/pro) -[**Commercial Support**](http://sheetjs.com/reinforcements) +[**Commercial Support**](http://sheetjs.com/support) [**Rendered Documentation**](https://sheetjs.gitbooks.io/docs/) +[**In-Browser Demos**](http://sheetjs.com/demos) + +[**Source Code**](http://git.io/xlsx) + [**File format support for known spreadsheet data formats:**](#file-formats) ![circo graph of format support](formats.png) diff --git a/bits/42_sstxml.js b/bits/42_sstxml.js index f3e2461..778356b 100644 --- a/bits/42_sstxml.js +++ b/bits/42_sstxml.js @@ -27,7 +27,7 @@ var parse_rs = (function parse_rs_factory() { var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g; /* 18.4.7 rPr CT_RPrElt */ var parse_rpr = function parse_rpr(rpr, intro, outro) { - var font = {}, cp = 65001; + var font = {}, cp = 65001, align = ""; var m = rpr.match(tagregex), i = 0; if(m) for(;i!=m.length; ++i) { var y = parsexmltag(m[i]); @@ -41,9 +41,11 @@ var parse_rs = (function parse_rs_factory() { /* 18.8.36 shadow CT_BooleanProperty */ /* ** not required . */ case '': - case '': break; + case '': font.shadow = 1; break; + case '': break; /* 18.4.1 charset CT_IntProperty TODO */ case '': - case '': break; + case '': font.outline = 1; break; + case '': break; /* 18.4.5 rFont CT_FontName */ case '': case '': font.u = 1; break; @@ -104,7 +113,7 @@ var parse_rs = (function parse_rs_factory() { case ''); + + if(font.b) { intro.push(""); outro.push(""); } + if(font.i) { intro.push(""); outro.push(""); } + if(font.strike) { intro.push(""); outro.push(""); } + + if(align == "superscript") align = "sup"; + else if(align == "subscript") align = "sub"; + if(align != "") { intro.push("<" + align + ">"); outro.push(""); } + outro.push(""); return cp; }; diff --git a/bits/48_stybin.js b/bits/48_stybin.js index 37ef6fe..987ad9b 100644 --- a/bits/48_stybin.js +++ b/bits/48_stybin.js @@ -47,6 +47,7 @@ function parse_sty_bin(data, themes, opts) { for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; styles.CellXf = []; + styles.Fonts = []; var state = []; var pass = false; recordhopper(data, function hopper_sty(val, R_n, RT) { @@ -54,7 +55,9 @@ function parse_sty_bin(data, themes, opts) { case 0x002C: /* 'BrtFmt' */ styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]); break; - case 0x002B: /* 'BrtFont' */ break; + case 0x002B: /* 'BrtFont' */ + styles.Fonts.push(val); + break; case 0x0401: /* 'BrtKnownFonts' */ break; case 0x002D: /* 'BrtFill' */ break; case 0x002E: /* 'BrtBorder' */ break; diff --git a/bits/90_utils.js b/bits/90_utils.js index 9df6d87..eb2f869 100644 --- a/bits/90_utils.js +++ b/bits/90_utils.js @@ -102,7 +102,7 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr } function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ { - var out = ""; + var out = []; var o = opts == null ? {} : opts; if(sheet == null || sheet["!ref"] == null) return ""; var r = safe_decode_range(sheet["!ref"]); @@ -116,10 +116,10 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ { row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o); if(row == null) { continue; } if(o.strip) row = row.replace(endregex,""); - out += row + RS; + out.push(row + RS); } delete o.dense; - return out; + return out.join(""); } function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { diff --git a/docbits/00_intro.md b/docbits/00_intro.md index db9cb64..47ee9fa 100644 --- a/docbits/00_intro.md +++ b/docbits/00_intro.md @@ -1,18 +1,23 @@ -# xlsx +# [:green_book: SheetJS js-xlsx](http://sheetjs.com) Parser and writer for various spreadsheet formats. Pure-JS cleanroom implementation from official specifications, related documents, and test files. Emphasis on parsing and writing robustness, cross-format feature compatibility with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. -[**In-Browser Demo**](http://oss.sheetjs.com/js-xlsx) +This is the community version. We also offer a pro version with performance +enhancements and additional features by request. -[**Source Code**](http://git.io/xlsx) +[**Pro Version**](http://sheetjs.com/pro) -[**Commercial Support**](http://sheetjs.com/reinforcements) +[**Commercial Support**](http://sheetjs.com/support) [**Rendered Documentation**](https://sheetjs.gitbooks.io/docs/) +[**In-Browser Demos**](http://sheetjs.com/demos) + +[**Source Code**](http://git.io/xlsx) + [**File format support for known spreadsheet data formats:**](#file-formats) ![circo graph of format support](formats.png) diff --git a/index.html b/index.html index ef3cef6..97730c2 100644 --- a/index.html +++ b/index.html @@ -18,26 +18,34 @@ #b64data{ width:100%; } +a { text-decoration: none } -JS-XLSX Live Demo
-Output Format: - +
-
Drop a spreadsheet file here to see sheet data
-

... or click here to select a file

+ ... or click here to select a file +
-Advanced Demo Options:
-Use Web Workers: (when available)
-Use Transferrables: (when available)
-Use readAsBinaryString: (when available)
+Advanced Demo Options: +Use Web Workers: (when available) +Use Transferrables: (when available) +Use readAsBinaryString: (when available) +

+

@@ -179,6 +187,15 @@ function to_formulae(workbook) { return result.join("\n"); } +function to_html(workbook) { + document.getElementById('htmlout').innerHTML = ""; + var result = []; + workbook.SheetNames.forEach(function(sheetName) { + var htmlstr = X.write(workbook, {sheet:sheetName, type:'binary', bookType:'html'}); + document.getElementById('htmlout').innerHTML += htmlstr; + }); +} + var tarea = document.getElementById('b64data'); function b64it() { if(typeof console !== 'undefined') console.log("onload", new Date()); @@ -197,6 +214,7 @@ function process_wb(wb) { case "form": output = to_formulae(wb); break; + case "html": return to_html(wb); default: output = to_csv(wb); } @@ -283,5 +301,16 @@ function handleFile(e) { if(xlf.addEventListener) xlf.addEventListener('change', handleFile, false); + diff --git a/test.js b/test.js index 81162e5..af7afa1 100644 --- a/test.js +++ b/test.js @@ -714,7 +714,7 @@ describe('parse features', function() { assert.equal(get_cell(ws, "B1").c[0].t, "Yegor Kozlov:\nfirst cell", "must have the concatenated texts"); if(i > 0) return; assert.equal(get_cell(ws, "B1").c[0].r, 'Yegor Kozlov:\r\nfirst cell', "must have the rich text representation"); - assert.equal(get_cell(ws, "B1").c[0].h, 'Yegor Kozlov:
first cell
', "must have the html representation"); + assert.equal(get_cell(ws, "B1").c[0].h, 'Yegor Kozlov:
first cell
', "must have the html representation"); }); }); [ diff --git a/xlsx.flow.js b/xlsx.flow.js index 6b24fd1..91b5e3a 100644 --- a/xlsx.flow.js +++ b/xlsx.flow.js @@ -5733,7 +5733,7 @@ var parse_rs = (function parse_rs_factory() { var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g; /* 18.4.7 rPr CT_RPrElt */ var parse_rpr = function parse_rpr(rpr, intro, outro) { - var font = {}, cp = 65001; + var font = {}, cp = 65001, align = ""; var m = rpr.match(tagregex), i = 0; if(m) for(;i!=m.length; ++i) { var y = parsexmltag(m[i]); @@ -5747,9 +5747,11 @@ var parse_rs = (function parse_rs_factory() { /* 18.8.36 shadow CT_BooleanProperty */ /* ** not required . */ case '': - case '': break; + case '': font.shadow = 1; break; + case '': break; /* 18.4.1 charset CT_IntProperty TODO */ case '': - case '': break; + case '': font.outline = 1; break; + case '': break; /* 18.4.5 rFont CT_FontName */ case '': case '': font.u = 1; break; @@ -5810,7 +5819,7 @@ var parse_rs = (function parse_rs_factory() { case ''); + + if(font.b) { intro.push(""); outro.push(""); } + if(font.i) { intro.push(""); outro.push(""); } + if(font.strike) { intro.push(""); outro.push(""); } + + if(align == "superscript") align = "sup"; + else if(align == "subscript") align = "sub"; + if(align != "") { intro.push("<" + align + ">"); outro.push(""); } + outro.push(""); return cp; }; @@ -6776,6 +6798,7 @@ function parse_sty_bin(data, themes, opts) { for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; styles.CellXf = []; + styles.Fonts = []; var state = []; var pass = false; recordhopper(data, function hopper_sty(val, R_n, RT) { @@ -6783,7 +6806,9 @@ function parse_sty_bin(data, themes, opts) { case 0x002C: /* 'BrtFmt' */ styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]); break; - case 0x002B: /* 'BrtFont' */ break; + case 0x002B: /* 'BrtFont' */ + styles.Fonts.push(val); + break; case 0x0401: /* 'BrtKnownFonts' */ break; case 0x002D: /* 'BrtFill' */ break; case 0x002E: /* 'BrtBorder' */ break; @@ -16504,7 +16529,7 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr } function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ { - var out = ""; + var out = []; var o = opts == null ? {} : opts; if(sheet == null || sheet["!ref"] == null) return ""; var r = safe_decode_range(sheet["!ref"]); @@ -16518,10 +16543,10 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ { row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o); if(row == null) { continue; } if(o.strip) row = row.replace(endregex,""); - out += row + RS; + out.push(row + RS); } delete o.dense; - return out; + return out.join(""); } function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { diff --git a/xlsx.js b/xlsx.js index a5ffee5..c38160c 100644 --- a/xlsx.js +++ b/xlsx.js @@ -5672,7 +5672,7 @@ var parse_rs = (function parse_rs_factory() { var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g; /* 18.4.7 rPr CT_RPrElt */ var parse_rpr = function parse_rpr(rpr, intro, outro) { - var font = {}, cp = 65001; + var font = {}, cp = 65001, align = ""; var m = rpr.match(tagregex), i = 0; if(m) for(;i!=m.length; ++i) { var y = parsexmltag(m[i]); @@ -5686,9 +5686,11 @@ var parse_rs = (function parse_rs_factory() { /* 18.8.36 shadow CT_BooleanProperty */ /* ** not required . */ case '': - case '': break; + case '': font.shadow = 1; break; + case '': break; /* 18.4.1 charset CT_IntProperty TODO */ case '': - case '': break; + case '': font.outline = 1; break; + case '': break; /* 18.4.5 rFont CT_FontName */ case '': case '': font.u = 1; break; @@ -5749,7 +5758,7 @@ var parse_rs = (function parse_rs_factory() { case ''); + + if(font.b) { intro.push(""); outro.push(""); } + if(font.i) { intro.push(""); outro.push(""); } + if(font.strike) { intro.push(""); outro.push(""); } + + if(align == "superscript") align = "sup"; + else if(align == "subscript") align = "sub"; + if(align != "") { intro.push("<" + align + ">"); outro.push(""); } + outro.push(""); return cp; }; @@ -6715,6 +6737,7 @@ function parse_sty_bin(data, themes, opts) { for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y]; styles.CellXf = []; + styles.Fonts = []; var state = []; var pass = false; recordhopper(data, function hopper_sty(val, R_n, RT) { @@ -6722,7 +6745,9 @@ function parse_sty_bin(data, themes, opts) { case 0x002C: /* 'BrtFmt' */ styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]); break; - case 0x002B: /* 'BrtFont' */ break; + case 0x002B: /* 'BrtFont' */ + styles.Fonts.push(val); + break; case 0x0401: /* 'BrtKnownFonts' */ break; case 0x002D: /* 'BrtFill' */ break; case 0x002E: /* 'BrtBorder' */ break; @@ -16434,7 +16459,7 @@ function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) { } function sheet_to_csv(sheet, opts) { - var out = ""; + var out = []; var o = opts == null ? {} : opts; if(sheet == null || sheet["!ref"] == null) return ""; var r = safe_decode_range(sheet["!ref"]); @@ -16448,10 +16473,10 @@ function sheet_to_csv(sheet, opts) { row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o); if(row == null) { continue; } if(o.strip) row = row.replace(endregex,""); - out += row + RS; + out.push(row + RS); } delete o.dense; - return out; + return out.join(""); } function sheet_to_txt(sheet, opts) {