rich text HTML + preview

This commit is contained in:
SheetJS 2017-04-19 23:24:48 -04:00
parent c356e91fdc
commit 6853c99ce5
9 changed files with 165 additions and 51 deletions

View File

@ -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)

View File

@ -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 '<shadow':
if(!y.val) break;
/* falls through */
case '<shadow>':
case '<shadow/>': break;
case '<shadow/>': font.shadow = 1; break;
case '</shadow>': break;
/* 18.4.1 charset CT_IntProperty TODO */
case '<charset':
@ -53,9 +55,11 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.2 outline CT_BooleanProperty TODO */
case '<outline':
if(!y.val) break;
/* falls through */
case '<outline>':
case '<outline/>': break;
case '<outline/>': font.outline = 1; break;
case '</outline>': break;
/* 18.4.5 rFont CT_FontName */
case '<rFont': font.name = y.val; break;
@ -73,7 +77,12 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.13 u CT_UnderlineProperty */
case '<u':
if(y.val == '0') break;
if(!y.val) break;
switch(y.val) {
case 'double': font.uval = "double"; break;
case 'singleAccounting': font.uval = "single-accounting"; break;
case 'doubleAccounting': font.uval = "double-accounting"; break;
}
/* falls through */
case '<u>':
case '<u/>': font.u = 1; break;
@ -104,7 +113,7 @@ var parse_rs = (function parse_rs_factory() {
case '<family': font.family = y.val; break;
/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
case '<vertAlign': break;
case '<vertAlign': align = y.val; break;
/* 18.8.35 scheme CT_FontScheme TODO */
case '<scheme': break;
@ -114,9 +123,22 @@ var parse_rs = (function parse_rs_factory() {
}
}
var style = [];
if(font.b) style.push("font-weight: bold;");
if(font.i) style.push("font-style: italic;");
if(font.u) style.push("text-decoration: underline;");
if(font.uval) style.push("text-underline-style:" + font.uval + ";");
if(font.sz) style.push("font-size:" + font.sz + ";");
if(font.outline) style.push("text-effect: outline;");
if(font.shadow) style.push("text-shadow: auto;");
intro.push('<span style="' + style.join("") + '">');
if(font.b) { intro.push("<b>"); outro.push("</b>"); }
if(font.i) { intro.push("<i>"); outro.push("</i>"); }
if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
if(align == "superscript") align = "sup";
else if(align == "subscript") align = "sub";
if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
outro.push("</span>");
return cp;
};

View File

@ -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;

View File

@ -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*/) {

View File

@ -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)

View File

@ -18,26 +18,34 @@
#b64data{
width:100%;
}
a { text-decoration: none }
</style>
</head>
<body>
<b>JS-XLSX Live Demo</b><br />
Output Format:
<select name="format" onchange="setfmt()">
<pre>
<b><a href="http://sheetjs.com">SheetJS Data Preview Live Demo</a></b>
(Base64 text works back to IE6; drag and drop works back to IE10)
<a href="https://github.com/SheetJS/js-xlsx">Source Code Repo</a>
<a href="https://github.com/SheetJS/js-xlsx/issues">Issues? Something look weird? Click here and report an issue</a>
Output Format: <select name="format" onchange="setfmt()">
<option value="csv" selected> CSV</option>
<option value="json"> JSON</option>
<option value="form"> FORMULAE</option>
<option value="html"> HTML</option>
</select><br />
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
<p><input type="file" name="xlfile" id="xlf" /> ... or click here to select a file</p>
<input type="file" name="xlfile" id="xlf" /> ... or click here to select a file
<textarea id="b64data">... or paste a base64-encoding here</textarea>
<input type="button" id="dotext" value="Click here to process the base64 text" onclick="b64it();"/><br />
Advanced Demo Options: <br />
Use Web Workers: (when available) <input type="checkbox" name="useworker" checked><br />
Use Transferrables: (when available) <input type="checkbox" name="xferable" checked><br />
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked><br />
<b>Advanced Demo Options:</b>
Use Web Workers: (when available) <input type="checkbox" name="useworker" checked>
Use Transferrables: (when available) <input type="checkbox" name="xferable" checked>
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked>
</pre>
<pre id="out"></pre>
<div id="htmlout"></div>
<br />
<!-- uncomment the next line here and in xlsxworker.js for encoding support -->
<script src="dist/cpexcel.js"></script>
@ -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);
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

View File

@ -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, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation");
assert.equal(get_cell(ws, "B1").c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation");
assert.equal(get_cell(ws, "B1").c[0].h, '<span style="font-size:8;"><b>Yegor Kozlov:</b></span><span style="font-size:8;"><br/>first cell</span>', "must have the html representation");
});
});
[

View File

@ -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 '<shadow':
if(!y.val) break;
/* falls through */
case '<shadow>':
case '<shadow/>': break;
case '<shadow/>': font.shadow = 1; break;
case '</shadow>': break;
/* 18.4.1 charset CT_IntProperty TODO */
case '<charset':
@ -5759,9 +5761,11 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.2 outline CT_BooleanProperty TODO */
case '<outline':
if(!y.val) break;
/* falls through */
case '<outline>':
case '<outline/>': break;
case '<outline/>': font.outline = 1; break;
case '</outline>': break;
/* 18.4.5 rFont CT_FontName */
case '<rFont': font.name = y.val; break;
@ -5779,7 +5783,12 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.13 u CT_UnderlineProperty */
case '<u':
if(y.val == '0') break;
if(!y.val) break;
switch(y.val) {
case 'double': font.uval = "double"; break;
case 'singleAccounting': font.uval = "single-accounting"; break;
case 'doubleAccounting': font.uval = "double-accounting"; break;
}
/* falls through */
case '<u>':
case '<u/>': font.u = 1; break;
@ -5810,7 +5819,7 @@ var parse_rs = (function parse_rs_factory() {
case '<family': font.family = y.val; break;
/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
case '<vertAlign': break;
case '<vertAlign': align = y.val; break;
/* 18.8.35 scheme CT_FontScheme TODO */
case '<scheme': break;
@ -5820,9 +5829,22 @@ var parse_rs = (function parse_rs_factory() {
}
}
var style = [];
if(font.b) style.push("font-weight: bold;");
if(font.i) style.push("font-style: italic;");
if(font.u) style.push("text-decoration: underline;");
if(font.uval) style.push("text-underline-style:" + font.uval + ";");
if(font.sz) style.push("font-size:" + font.sz + ";");
if(font.outline) style.push("text-effect: outline;");
if(font.shadow) style.push("text-shadow: auto;");
intro.push('<span style="' + style.join("") + '">');
if(font.b) { intro.push("<b>"); outro.push("</b>"); }
if(font.i) { intro.push("<i>"); outro.push("</i>"); }
if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
if(align == "superscript") align = "sup";
else if(align == "subscript") align = "sub";
if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
outro.push("</span>");
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*/) {

47
xlsx.js
View File

@ -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 '<shadow':
if(!y.val) break;
/* falls through */
case '<shadow>':
case '<shadow/>': break;
case '<shadow/>': font.shadow = 1; break;
case '</shadow>': break;
/* 18.4.1 charset CT_IntProperty TODO */
case '<charset':
@ -5698,9 +5700,11 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.2 outline CT_BooleanProperty TODO */
case '<outline':
if(!y.val) break;
/* falls through */
case '<outline>':
case '<outline/>': break;
case '<outline/>': font.outline = 1; break;
case '</outline>': break;
/* 18.4.5 rFont CT_FontName */
case '<rFont': font.name = y.val; break;
@ -5718,7 +5722,12 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.13 u CT_UnderlineProperty */
case '<u':
if(y.val == '0') break;
if(!y.val) break;
switch(y.val) {
case 'double': font.uval = "double"; break;
case 'singleAccounting': font.uval = "single-accounting"; break;
case 'doubleAccounting': font.uval = "double-accounting"; break;
}
/* falls through */
case '<u>':
case '<u/>': font.u = 1; break;
@ -5749,7 +5758,7 @@ var parse_rs = (function parse_rs_factory() {
case '<family': font.family = y.val; break;
/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
case '<vertAlign': break;
case '<vertAlign': align = y.val; break;
/* 18.8.35 scheme CT_FontScheme TODO */
case '<scheme': break;
@ -5759,9 +5768,22 @@ var parse_rs = (function parse_rs_factory() {
}
}
var style = [];
if(font.b) style.push("font-weight: bold;");
if(font.i) style.push("font-style: italic;");
if(font.u) style.push("text-decoration: underline;");
if(font.uval) style.push("text-underline-style:" + font.uval + ";");
if(font.sz) style.push("font-size:" + font.sz + ";");
if(font.outline) style.push("text-effect: outline;");
if(font.shadow) style.push("text-shadow: auto;");
intro.push('<span style="' + style.join("") + '">');
if(font.b) { intro.push("<b>"); outro.push("</b>"); }
if(font.i) { intro.push("<i>"); outro.push("</i>"); }
if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
if(align == "superscript") align = "sup";
else if(align == "subscript") align = "sub";
if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
outro.push("</span>");
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) {