forked from sheetjs/sheetjs
version bump 0.7.5: more performance
- eliminated functional constructs in hot functions - format try-catch block extracted into new function - cpexcel + codepage updated to 1.2.0 - more efficient (and correct) clean implementation of RGB/HSL/tint algorithms - xlsx binary --all option enables every extra formatting and saving option - column widths parsed and saved (requires cellStyles:true)
This commit is contained in:
parent
d882757c0a
commit
009946339c
@ -22,6 +22,7 @@ program
|
||||
.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)')
|
||||
.option('--no-sst', 'do not generate sst')
|
||||
.option('--perf', 'do not generate output')
|
||||
.option('--all', 'parse everything; XLS[XMB] write as much as possible')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents')
|
||||
.option('-q, --quiet', 'quiet mode');
|
||||
@ -62,6 +63,12 @@ if(program.xlsx || program.xlsm || program.xlsb) {
|
||||
else if(program.formulae);
|
||||
else opts.cellFormula = false;
|
||||
|
||||
if(program.all) {
|
||||
opts.cellFormula = true;
|
||||
opts.cellNF = true;
|
||||
opts.cellStyles = true;
|
||||
}
|
||||
|
||||
if(program.dev) {
|
||||
X.verbose = 2;
|
||||
opts.WTF = true;
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.7.4';
|
||||
XLSX.version = '0.7.5';
|
||||
|
@ -6,11 +6,16 @@ function parsexmltag(tag) {
|
||||
var words = tag.split(/\s+/);
|
||||
var z = {'0': words[0]};
|
||||
if(words.length === 1) return z;
|
||||
(tag.match(attregexg) || []).map(function(x){
|
||||
var y=x.match(attregex);
|
||||
y[1] = y[1].replace(/xmlns:/,"xmlns");
|
||||
z[y[1].replace(/^[a-zA-Z]*:/,"")] = y[2].substr(1,y[2].length-2);
|
||||
});
|
||||
var m = tag.match(attregexg), y, j, w, i;
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
y = m[i].match(attregex);
|
||||
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].substr(1,y[2].length-2);
|
||||
else {
|
||||
if(y[1].substr(0,6) === "xmlns:") w = "xmlns"+y[1].substr(6);
|
||||
else w = y[1].substr(j+1);
|
||||
z[w] = y[2].substr(1,y[2].length-2);
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
@ -27,7 +32,7 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
function unescapexml(text){
|
||||
var s = text + '';
|
||||
s = s.replace(/"/g, '"').replace(/'/g, "'").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
||||
s = s.replace(/&[a-z]*;/g, function($$) { return encodings[$$]; });
|
||||
return s.replace(/_x([0-9a-fA-F]*)_/g,function(m,c) {return _chr(parseInt(c,16));});
|
||||
}
|
||||
function escapexml(text){
|
61
bits/45_styutils.js
Normal file
61
bits/45_styutils.js
Normal file
@ -0,0 +1,61 @@
|
||||
var hex2RGB = function(h) {return h.substr(h[0]==="#"?1:0,6).match(/../g).map(function(x) { return parseInt(x,16); });};
|
||||
var rgb2Hex = function(rgb) {
|
||||
for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
|
||||
return o.toString(16).toUpperCase().substr(1);
|
||||
};
|
||||
|
||||
var rgb2HSL = function(rgb) {
|
||||
var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
|
||||
var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
|
||||
if(C === 0) return [0, 0, R];
|
||||
|
||||
var H6 = 0, S = 0, L2 = (M + m);
|
||||
S = C / (L2 > 1 ? 2 - L2 : L2);
|
||||
switch(M){
|
||||
case R: H6 = ((G - B) / C + 6)%6; break;
|
||||
case G: H6 = ((B - R) / C + 2); break;
|
||||
case B: H6 = ((R - G) / C + 4); break;
|
||||
}
|
||||
return [H6 / 6, S, L2 / 2];
|
||||
};
|
||||
|
||||
var hsl2RGB = function(hsl){
|
||||
var H = hsl[0], S = hsl[1], L = hsl[2];
|
||||
var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
|
||||
var rgb = [m,m,m], h6 = 6*H;
|
||||
|
||||
var X;
|
||||
if(S !== 0) switch(h6|0) {
|
||||
case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
|
||||
case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
|
||||
case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
|
||||
case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
|
||||
case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
|
||||
case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
|
||||
}
|
||||
for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
|
||||
return rgb;
|
||||
};
|
||||
|
||||
/* 18.8.3 bgColor tint algorithm */
|
||||
function rgb_tint(hex, tint) {
|
||||
if(tint === 0) return hex;
|
||||
var hsl = rgb2HSL(hex2RGB(hex));
|
||||
if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
|
||||
else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
|
||||
return rgb2Hex(hsl2RGB(hsl));
|
||||
}
|
||||
|
||||
/* 18.3.1.13 width calculations */
|
||||
var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
function width2px(width) { return (( width + ((128/MDW)|0)/256 )* MDW )|0; }
|
||||
function px2char(px) { return (((px - 5)/MDW * 100 + 0.5)|0)/100; }
|
||||
function char2width(chr) { return (((chr * MDW + 5)/MDW*256)|0)/256; }
|
||||
function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
|
||||
function find_mdw(collw, coll) {
|
||||
if(cycle_width(collw) != collw) {
|
||||
for(MDW=DEF_MDW; MDW>MIN_MDW; --MDW) if(cycle_width(collw) === collw) break;
|
||||
if(MDW === MIN_MDW) for(MDW=DEF_MDW+1; MDW<MAX_MDW; ++MDW) if(cycle_width(collw) === collw) break;
|
||||
if(MDW === MAX_MDW) MDW = DEF_MDW;
|
||||
}
|
||||
}
|
@ -1,112 +1,6 @@
|
||||
RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
||||
|
||||
/* Various RGB/HSL utility functions - might want to put these elsewhere. */
|
||||
/* From http://www.javascripter.net/faq/hextorgb.htm, usage: var X = hexToX('FFFFFF') */
|
||||
function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}
|
||||
function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
|
||||
function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
|
||||
function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
|
||||
/* From http://www.javascripter.net/faq/rgbtohex.htm, usage: var RGB = rgbToHex(R, G, B) */
|
||||
function toHex(n) {
|
||||
n = parseInt(n,10);
|
||||
if (isNaN(n)) return "00";
|
||||
n = Math.max(0,Math.min(n,255));
|
||||
return "0123456789ABCDEF".charAt((n-n%16)/16)
|
||||
+ "0123456789ABCDEF".charAt(n%16);
|
||||
}
|
||||
function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)}
|
||||
/* From the specification. */
|
||||
var HLSMAX = 255;
|
||||
/* From https://gist.github.com/mjackson/5311256 via http://stackoverflow.com/a/9493060 */
|
||||
/**
|
||||
* Converts an RGB color value to HSL. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes r, g, and b are contained in the set [0, 255] and
|
||||
* returns h, s, and l in the set [0, 1].
|
||||
*
|
||||
* @param Number r The red color value
|
||||
* @param Number g The green color value
|
||||
* @param Number b The blue color value
|
||||
* @return Array The HSL representation
|
||||
*/
|
||||
function rgbToHsl(r, g, b){
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if(max == min){
|
||||
h = s = 0; // achromatic
|
||||
}else{
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch(max){
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
case b: h = (r - g) / d + 4; break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [h, s, l];
|
||||
}
|
||||
/**
|
||||
* Converts an HSL color value to RGB. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||
* returns r, g, and b in the set [0, 255].
|
||||
*
|
||||
* @param Number h The hue
|
||||
* @param Number s The saturation
|
||||
* @param Number l The lightness
|
||||
* @return Array The RGB representation
|
||||
*/
|
||||
function hslToRgb(h, s, l){
|
||||
var r, g, b;
|
||||
|
||||
if(s == 0){
|
||||
r = g = b = l; // achromatic
|
||||
}else{
|
||||
function hue2rgb(p, q, t){
|
||||
if(t < 0) t += 1;
|
||||
if(t > 1) t -= 1;
|
||||
if(t < 1/6) return p + (q - p) * 6 * t;
|
||||
if(t < 1/2) return q;
|
||||
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
||||
}
|
||||
/* Utility function to apply tint to an RGB color. */
|
||||
function rgb_tint(rgb, tint) {
|
||||
var r = hexToR(rgb),
|
||||
g = hexToG(rgb),
|
||||
b = hexToB(rgb),
|
||||
hsl = rgbToHsl(r, g, b);
|
||||
|
||||
/* Apply tint as described in pages 1757-1758 of the ECMA Office Open XML specification. */
|
||||
/* NOTE: This is totally messed up... see http://social.msdn.microsoft.com/Forums/en-US/e9d8c136-6d62-4098-9b1b-dac786149f43/excel-color-tint-algorithm-incorrect */
|
||||
if (tint < 0) {
|
||||
hsl[2] = hsl[2] * (1.0 + tint);
|
||||
} else if (tint > 0) {
|
||||
hsl[2] = hsl[2] * (1.0 + tint);
|
||||
|
||||
// XXX This doesn't work...
|
||||
//hsl[2] = hsl[2] * (1.0 - tint) + (HLSMAX - HLSMAX * (1.0 - tint));
|
||||
}
|
||||
|
||||
rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
|
||||
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
/* 20.1.6.2 clrScheme CT_ColorScheme */
|
||||
function parse_clrScheme(t, opts) {
|
||||
themes.themeElements.clrScheme = [];
|
||||
var color = {};
|
||||
@ -176,7 +70,7 @@ function parse_theme_xml(data, opts) {
|
||||
|
||||
var t;
|
||||
|
||||
/* clrScheme */
|
||||
/* clrScheme CT_ColorScheme */
|
||||
if((t=data.match(/<a:clrScheme([^>]*)>.*<\/a:clrScheme>/))) parse_clrScheme(t, opts);
|
||||
|
||||
return themes;
|
41
bits/66_wscommon.js
Normal file
41
bits/66_wscommon.js
Normal file
@ -0,0 +1,41 @@
|
||||
var strs = {}; // shared strings
|
||||
var _ssfopts = {}; // spreadsheet formatting options
|
||||
|
||||
RELS.WS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
||||
|
||||
function get_sst_id(sst, str) {
|
||||
for(var i = 0; i != sst.length; ++i) if(sst[i].t === str) { sst.Count ++; return i; }
|
||||
sst[sst.length] = {t:str}; sst.Count ++; sst.Unique ++; return sst.length-1;
|
||||
}
|
||||
|
||||
function get_cell_style(styles, cell, opts) {
|
||||
var z = opts.revssf[cell.z||"General"];
|
||||
for(var i = 0; i != styles.length; ++i) if(styles[i].numFmtId === z) return i;
|
||||
styles[styles.length] = {
|
||||
numFmtId:z,
|
||||
fontId:0,
|
||||
fillId:0,
|
||||
borderId:0,
|
||||
xfId:0,
|
||||
applyNumberFormat:1
|
||||
};
|
||||
return styles.length-1;
|
||||
}
|
||||
|
||||
function safe_format(p, fmtid, fillid, opts) {
|
||||
try {
|
||||
p.w = SSF.format(fmtid,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[fmtid];
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
if(fillid) try {
|
||||
p.s = styles.Fills[fillid];
|
||||
if (p.s.fgColor && p.s.fgColor.theme) {
|
||||
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
|
||||
if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
|
||||
}
|
||||
if (p.s.bgColor && p.s.bgColor.theme) {
|
||||
p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
|
||||
if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
|
||||
}
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
}
|
@ -17,6 +17,27 @@ function parse_ws_xml(data, opts, rels) {
|
||||
});
|
||||
}
|
||||
|
||||
/* 18.3.1.17 cols CT_Cols */
|
||||
var columns = [];
|
||||
if(opts.cellStyles && data.match(/<\/cols>/)) {
|
||||
/* 18.3.1.13 col CT_Col */
|
||||
var cols = data.match(/<col[^>]*\/>/g);
|
||||
var seencol = false;
|
||||
for(var coli = 0; coli != cols.length; ++coli) {
|
||||
var coll = parsexmltag(cols[coli]);
|
||||
delete coll[0];
|
||||
var colm=Number(coll.min)-1, colM=Number(coll.max)-1;
|
||||
delete coll.min, coll.max;
|
||||
if(!seencol && coll.width) { seencol = true; find_mdw(+coll.width, coll); }
|
||||
if(coll.width) {
|
||||
coll.wpx = width2px(+coll.width);
|
||||
coll.wch = px2char(coll.wpx);
|
||||
coll.MDW = MDW;
|
||||
}
|
||||
while(colm <= colM) columns[colm++] = coll;
|
||||
}
|
||||
}
|
||||
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var sidx = 0;
|
||||
|
||||
@ -34,7 +55,8 @@ function parse_ws_xml(data, opts, rels) {
|
||||
if(refguess.e.r < row.r - 1) refguess.e.r = row.r - 1;
|
||||
/* 18.3.1.4 c CT_Cell */
|
||||
var cells = x.substr(x.indexOf('>')+1).split(/<(?:\w+:)?c /);
|
||||
for(var ix = 0, c=cells[0]; ix != cells.length; ++ix,c=cells[ix]) {
|
||||
for(var ix = 0, c=cells[0]; ix != cells.length; ++ix) {
|
||||
c = cells[ix];
|
||||
if(c === "" || c.trim() === "") continue;
|
||||
var cref = c.match(/r=["']([^"']*)["']/), idx = ix;
|
||||
c = "<c " + c;
|
||||
@ -85,21 +107,9 @@ function parse_ws_xml(data, opts, rels) {
|
||||
if(cf && cf.numFmtId) fmtid = cf.numFmtId;
|
||||
if(opts.cellStyles && cf && cf.fillId) fillid = cf.fillId;
|
||||
}
|
||||
try {
|
||||
p.w = SSF.format(fmtid,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[fmtid];
|
||||
if(fillid) {
|
||||
p.s = styles.Fills[fillid];
|
||||
if (p.s.fgColor && p.s.fgColor.theme) {
|
||||
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
|
||||
}
|
||||
if (p.s.bgColor && p.s.bgColor.theme) {
|
||||
p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
|
||||
}
|
||||
}
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
safe_format(p, fmtid, fillid, opts);
|
||||
s[cell.r] = p;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* 18.3.1.48 hyperlinks CT_Hyperlinks */
|
||||
@ -134,9 +144,11 @@ function parse_ws_xml(data, opts, rels) {
|
||||
}
|
||||
}
|
||||
if(mergecells.length > 0) s["!merges"] = mergecells;
|
||||
if(columns.length > 0) s["!cols"] = columns;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
var WS_XML_ROOT = writextag('worksheet', null, {
|
||||
'xmlns': XMLNS.main[0],
|
||||
'xmlns:r': XMLNS.r
|
||||
@ -176,12 +188,28 @@ var write_ws_xml_data = function(ws, opts, idx, wb) {
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
var write_ws_cols = function(ws, cols) {
|
||||
var o = ["<cols>"], col, width;
|
||||
for(var i = 0; i != cols.length; ++i) {
|
||||
if(!(col = cols[i])) continue;
|
||||
var p = {min:i+1,max:i+1};
|
||||
/* wch (chars), wpx (pixels) */
|
||||
width = -1;
|
||||
if(col.wpx) width = px2char(col.wpx);
|
||||
else if(col.wch) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth= 1; }
|
||||
o.push(writextag('col', null, p));
|
||||
}
|
||||
o.push("</cols>");
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
var write_ws_xml = function(idx, opts, wb) {
|
||||
var o = [], s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}, sidx = 0, rdata = "";
|
||||
o.push(XML_HEADER);
|
||||
o.push(WS_XML_ROOT);
|
||||
o.push(writextag('dimension', null, {'ref': ws['!ref'] || 'A1'}));
|
||||
|
||||
if((ws['!cols']||[]).length > 0) o.push(write_ws_cols(ws, ws['!cols']));
|
||||
sidx = o.length;
|
||||
o.push(writextag('sheetData', null));
|
||||
if(ws['!ref']) rdata = write_ws_xml_data(ws, opts, idx, wb);
|
@ -176,10 +176,7 @@ var parse_ws_bin = function(data, opts, rels) {
|
||||
case 'str': p.v = utf8read(val[1]); break;
|
||||
}
|
||||
if(opts.cellFormula && val.length > 3) p.f = val[3];
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) try {
|
||||
p.w = SSF.format(cf.ifmt,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[cf.ifmt];
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
|
||||
s[encode_cell({c:val[0].c,r:row.r})] = p;
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > val[0].c) refguess.s.c = val[0].c;
|
@ -1,23 +0,0 @@
|
||||
var strs = {}; // shared strings
|
||||
var _ssfopts = {}; // spreadsheet formatting options
|
||||
|
||||
RELS.WS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
|
||||
|
||||
function get_sst_id(sst, str) {
|
||||
for(var i = 0; i != sst.length; ++i) if(sst[i].t === str) { sst.Count ++; return i; }
|
||||
sst[sst.length] = {t:str}; sst.Count ++; sst.Unique ++; return sst.length-1;
|
||||
}
|
||||
|
||||
function get_cell_style(styles, cell, opts) {
|
||||
var z = opts.revssf[cell.z||"General"];
|
||||
for(var i = 0; i != styles.length; ++i) if(styles[i].numFmtId === z) return i;
|
||||
styles[styles.length] = {
|
||||
numFmtId:z,
|
||||
fontId:0,
|
||||
fillId:0,
|
||||
borderId:0,
|
||||
xfId:0,
|
||||
applyNumberFormat:1
|
||||
};
|
||||
return styles.length-1;
|
||||
}
|
@ -125,14 +125,16 @@ var WB_XML_ROOT = writextag('workbook', null, {
|
||||
'xmlns:r': XMLNS.r
|
||||
});
|
||||
|
||||
function safe1904(wb) {
|
||||
/* TODO: store date1904 somewhere else */
|
||||
try { return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { return "false"; }
|
||||
}
|
||||
|
||||
var write_wb_xml = function(wb, opts) {
|
||||
var o = [];
|
||||
o.push(XML_HEADER);
|
||||
o.push(WB_XML_ROOT);
|
||||
/* TODO: put this somewhere else */
|
||||
var date1904 = "false";
|
||||
try { date1904 = parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { date1904 = "false"; }
|
||||
o.push(writextag('workbookPr', null, {date1904:date1904}));
|
||||
o.push(writextag('workbookPr', null, {date1904:safe1904(wb)}));
|
||||
o.push("<sheets>");
|
||||
var i = 1;
|
||||
wb.SheetNames.forEach(function(s) {
|
||||
|
861
dist/cpexcel.js
vendored
861
dist/cpexcel.js
vendored
File diff suppressed because it is too large
Load Diff
8
dist/xlsx.core.min.js
vendored
8
dist/xlsx.core.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.core.min.map
vendored
2
dist/xlsx.core.min.map
vendored
File diff suppressed because one or more lines are too long
18
dist/xlsx.full.min.js
vendored
18
dist/xlsx.full.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.full.min.map
vendored
2
dist/xlsx.full.min.map
vendored
File diff suppressed because one or more lines are too long
367
dist/xlsx.js
vendored
367
dist/xlsx.js
vendored
@ -2,7 +2,7 @@
|
||||
/* vim: set ts=2: */
|
||||
var XLSX = {};
|
||||
(function(XLSX){
|
||||
XLSX.version = '0.7.4';
|
||||
XLSX.version = '0.7.5';
|
||||
var current_codepage = 1252, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
@ -655,11 +655,16 @@ function parsexmltag(tag) {
|
||||
var words = tag.split(/\s+/);
|
||||
var z = {'0': words[0]};
|
||||
if(words.length === 1) return z;
|
||||
(tag.match(attregexg) || []).map(function(x){
|
||||
var y=x.match(attregex);
|
||||
y[1] = y[1].replace(/xmlns:/,"xmlns");
|
||||
z[y[1].replace(/^[a-zA-Z]*:/,"")] = y[2].substr(1,y[2].length-2);
|
||||
});
|
||||
var m = tag.match(attregexg), y, j, w, i;
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
y = m[i].match(attregex);
|
||||
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].substr(1,y[2].length-2);
|
||||
else {
|
||||
if(y[1].substr(0,6) === "xmlns:") w = "xmlns"+y[1].substr(6);
|
||||
else w = y[1].substr(j+1);
|
||||
z[w] = y[2].substr(1,y[2].length-2);
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
@ -676,7 +681,7 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
function unescapexml(text){
|
||||
var s = text + '';
|
||||
s = s.replace(/"/g, '"').replace(/'/g, "'").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
||||
s = s.replace(/&[a-z]*;/g, function($$) { return encodings[$$]; });
|
||||
return s.replace(/_x([0-9a-fA-F]*)_/g,function(m,c) {return _chr(parseInt(c,16));});
|
||||
}
|
||||
function escapexml(text){
|
||||
@ -1825,6 +1830,67 @@ var parse_sst_bin = function(data, opts) {
|
||||
};
|
||||
|
||||
var write_sst_bin = function(sst, opts) { };
|
||||
var hex2RGB = function(h) {return h.substr(h[0]==="#"?1:0,6).match(/../g).map(function(x) { return parseInt(x,16); });};
|
||||
var rgb2Hex = function(rgb) {
|
||||
for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
|
||||
return o.toString(16).toUpperCase().substr(1);
|
||||
};
|
||||
|
||||
var rgb2HSL = function(rgb) {
|
||||
var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
|
||||
var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
|
||||
if(C === 0) return [0, 0, R];
|
||||
|
||||
var H6 = 0, S = 0, L2 = (M + m);
|
||||
S = C / (L2 > 1 ? 2 - L2 : L2);
|
||||
switch(M){
|
||||
case R: H6 = ((G - B) / C + 6)%6; break;
|
||||
case G: H6 = ((B - R) / C + 2); break;
|
||||
case B: H6 = ((R - G) / C + 4); break;
|
||||
}
|
||||
return [H6 / 6, S, L2 / 2];
|
||||
};
|
||||
|
||||
var hsl2RGB = function(hsl){
|
||||
var H = hsl[0], S = hsl[1], L = hsl[2];
|
||||
var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
|
||||
var rgb = [m,m,m], h6 = 6*H;
|
||||
|
||||
var X;
|
||||
if(S !== 0) switch(h6|0) {
|
||||
case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
|
||||
case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
|
||||
case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
|
||||
case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
|
||||
case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
|
||||
case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
|
||||
}
|
||||
for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
|
||||
return rgb;
|
||||
};
|
||||
|
||||
/* 18.8.3 bgColor tint algorithm */
|
||||
function rgb_tint(hex, tint) {
|
||||
if(tint === 0) return hex;
|
||||
var hsl = rgb2HSL(hex2RGB(hex));
|
||||
if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
|
||||
else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
|
||||
return rgb2Hex(hsl2RGB(hsl));
|
||||
}
|
||||
|
||||
/* 18.3.1.13 width calculations */
|
||||
var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
function width2px(width) { return (( width + ((128/MDW)|0)/256 )* MDW )|0; }
|
||||
function px2char(px) { return (((px - 5)/MDW * 100 + 0.5)|0)/100; }
|
||||
function char2width(chr) { return (((chr * MDW + 5)/MDW*256)|0)/256; }
|
||||
function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
|
||||
function find_mdw(collw, coll) {
|
||||
if(cycle_width(collw) != collw) {
|
||||
for(MDW=DEF_MDW; MDW>MIN_MDW; --MDW) if(cycle_width(collw) === collw) break;
|
||||
if(MDW === MIN_MDW) for(MDW=DEF_MDW+1; MDW<MAX_MDW; ++MDW) if(cycle_width(collw) === collw) break;
|
||||
if(MDW === MAX_MDW) MDW = DEF_MDW;
|
||||
}
|
||||
}
|
||||
var styles = {}; // shared styles
|
||||
|
||||
var themes = {}; // shared themes
|
||||
@ -2111,113 +2177,7 @@ function parse_sty_bin(data, opts) {
|
||||
function write_sty_bin(data, opts) { }
|
||||
RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
||||
|
||||
/* Various RGB/HSL utility functions - might want to put these elsewhere. */
|
||||
/* From http://www.javascripter.net/faq/hextorgb.htm, usage: var X = hexToX('FFFFFF') */
|
||||
function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}
|
||||
function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
|
||||
function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
|
||||
function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
|
||||
/* From http://www.javascripter.net/faq/rgbtohex.htm, usage: var RGB = rgbToHex(R, G, B) */
|
||||
function toHex(n) {
|
||||
n = parseInt(n,10);
|
||||
if (isNaN(n)) return "00";
|
||||
n = Math.max(0,Math.min(n,255));
|
||||
return "0123456789ABCDEF".charAt((n-n%16)/16)
|
||||
+ "0123456789ABCDEF".charAt(n%16);
|
||||
}
|
||||
function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)}
|
||||
/* From the specification. */
|
||||
var HLSMAX = 255;
|
||||
/* From https://gist.github.com/mjackson/5311256 via http://stackoverflow.com/a/9493060 */
|
||||
/**
|
||||
* Converts an RGB color value to HSL. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes r, g, and b are contained in the set [0, 255] and
|
||||
* returns h, s, and l in the set [0, 1].
|
||||
*
|
||||
* @param Number r The red color value
|
||||
* @param Number g The green color value
|
||||
* @param Number b The blue color value
|
||||
* @return Array The HSL representation
|
||||
*/
|
||||
function rgbToHsl(r, g, b){
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if(max == min){
|
||||
h = s = 0; // achromatic
|
||||
}else{
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch(max){
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
case b: h = (r - g) / d + 4; break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [h, s, l];
|
||||
}
|
||||
/**
|
||||
* Converts an HSL color value to RGB. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||
* returns r, g, and b in the set [0, 255].
|
||||
*
|
||||
* @param Number h The hue
|
||||
* @param Number s The saturation
|
||||
* @param Number l The lightness
|
||||
* @return Array The RGB representation
|
||||
*/
|
||||
function hslToRgb(h, s, l){
|
||||
var r, g, b;
|
||||
|
||||
if(s == 0){
|
||||
r = g = b = l; // achromatic
|
||||
}else{
|
||||
function hue2rgb(p, q, t){
|
||||
if(t < 0) t += 1;
|
||||
if(t > 1) t -= 1;
|
||||
if(t < 1/6) return p + (q - p) * 6 * t;
|
||||
if(t < 1/2) return q;
|
||||
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
||||
}
|
||||
/* Utility function to apply tint to an RGB color. */
|
||||
function rgb_tint(rgb, tint) {
|
||||
var r = hexToR(rgb),
|
||||
g = hexToG(rgb),
|
||||
b = hexToB(rgb),
|
||||
hsl = rgbToHsl(r, g, b);
|
||||
|
||||
/* Apply tint as described in pages 1757-1758 of the ECMA Office Open XML specification. */
|
||||
/* NOTE: This is totally messed up... see http://social.msdn.microsoft.com/Forums/en-US/e9d8c136-6d62-4098-9b1b-dac786149f43/excel-color-tint-algorithm-incorrect */
|
||||
if (tint < 0) {
|
||||
hsl[2] = hsl[2] * (1.0 + tint);
|
||||
} else if (tint > 0) {
|
||||
hsl[2] = hsl[2] * (1.0 + tint);
|
||||
|
||||
// XXX This doesn't work...
|
||||
//hsl[2] = hsl[2] * (1.0 - tint) + (HLSMAX - HLSMAX * (1.0 - tint));
|
||||
}
|
||||
|
||||
rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
|
||||
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
/* 20.1.6.2 clrScheme CT_ColorScheme */
|
||||
function parse_clrScheme(t, opts) {
|
||||
themes.themeElements.clrScheme = [];
|
||||
var color = {};
|
||||
@ -2287,7 +2247,7 @@ function parse_theme_xml(data, opts) {
|
||||
|
||||
var t;
|
||||
|
||||
/* clrScheme */
|
||||
/* clrScheme CT_ColorScheme */
|
||||
if((t=data.match(/<a:clrScheme([^>]*)>.*<\/a:clrScheme>/))) parse_clrScheme(t, opts);
|
||||
|
||||
return themes;
|
||||
@ -2342,6 +2302,48 @@ function parse_cc_bin(data, opts) {
|
||||
}
|
||||
|
||||
function write_cc_bin(data, opts) { }
|
||||
|
||||
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
|
||||
for(var i = 0; i != dirComments.length; ++i) {
|
||||
var canonicalpath=dirComments[i];
|
||||
var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
|
||||
if(!comments || !comments.length) continue;
|
||||
// find the sheets targeted by these comments
|
||||
var sheetNames = keys(sheets);
|
||||
for(var j = 0; j != sheetNames.length; ++j) {
|
||||
var sheetName = sheetNames[j];
|
||||
var rels = sheetRels[sheetName];
|
||||
if(rels) {
|
||||
var rel = rels[canonicalpath];
|
||||
if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertCommentsIntoSheet(sheetName, sheet, comments) {
|
||||
comments.forEach(function(comment) {
|
||||
var cell = sheet[comment.ref];
|
||||
if (!cell) {
|
||||
cell = {};
|
||||
sheet[comment.ref] = cell;
|
||||
var range = decode_range(sheet["!ref"]||"BDWGO1000001:A1");
|
||||
var thisCell = decode_cell(comment.ref);
|
||||
if(range.s.r > thisCell.r) range.s.r = thisCell.r;
|
||||
if(range.e.r < thisCell.r) range.e.r = thisCell.r;
|
||||
if(range.s.c > thisCell.c) range.s.c = thisCell.c;
|
||||
if(range.e.c < thisCell.c) range.e.c = thisCell.c;
|
||||
var encoded = encode_range(range);
|
||||
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
|
||||
}
|
||||
|
||||
if (!cell.c) cell.c = [];
|
||||
var o = {a: comment.author, t: comment.t, r: comment.r};
|
||||
if(comment.h) o.h = comment.h;
|
||||
cell.c.push(o);
|
||||
});
|
||||
}
|
||||
|
||||
/* 18.7.3 CT_Comment */
|
||||
function parse_comments_xml(data, opts) {
|
||||
if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
|
||||
@ -2415,48 +2417,6 @@ function parse_comments_bin(data, opts) {
|
||||
}
|
||||
|
||||
function write_comments_bin(data, opts) { }
|
||||
|
||||
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
|
||||
for(var i = 0; i != dirComments.length; ++i) {
|
||||
var canonicalpath=dirComments[i];
|
||||
var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
|
||||
if(!comments || !comments.length) continue;
|
||||
// find the sheets targeted by these comments
|
||||
var sheetNames = keys(sheets);
|
||||
for(var j = 0; j != sheetNames.length; ++j) {
|
||||
var sheetName = sheetNames[j];
|
||||
var rels = sheetRels[sheetName];
|
||||
if(rels) {
|
||||
var rel = rels[canonicalpath];
|
||||
if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertCommentsIntoSheet(sheetName, sheet, comments) {
|
||||
comments.forEach(function(comment) {
|
||||
var cell = sheet[comment.ref];
|
||||
if (!cell) {
|
||||
cell = {};
|
||||
sheet[comment.ref] = cell;
|
||||
var range = decode_range(sheet["!ref"]||"BDWGO1000001:A1");
|
||||
var thisCell = decode_cell(comment.ref);
|
||||
if(range.s.r > thisCell.r) range.s.r = thisCell.r;
|
||||
if(range.e.r < thisCell.r) range.e.r = thisCell.r;
|
||||
if(range.s.c > thisCell.c) range.s.c = thisCell.c;
|
||||
if(range.e.c < thisCell.c) range.e.c = thisCell.c;
|
||||
var encoded = encode_range(range);
|
||||
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
|
||||
}
|
||||
|
||||
if (!cell.c) cell.c = [];
|
||||
var o = {a: comment.author, t: comment.t, r: comment.r};
|
||||
if(comment.h) o.h = comment.h;
|
||||
cell.c.push(o);
|
||||
});
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.5.97.4 CellParsedFormula TODO: use similar logic to js-xls */
|
||||
var parse_CellParsedFormula = function(data, length) {
|
||||
var cce = data.read_shift(4);
|
||||
@ -2485,6 +2445,24 @@ function get_cell_style(styles, cell, opts) {
|
||||
};
|
||||
return styles.length-1;
|
||||
}
|
||||
|
||||
function safe_format(p, fmtid, fillid, opts) {
|
||||
try {
|
||||
p.w = SSF.format(fmtid,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[fmtid];
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
if(fillid) try {
|
||||
p.s = styles.Fills[fillid];
|
||||
if (p.s.fgColor && p.s.fgColor.theme) {
|
||||
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
|
||||
if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
|
||||
}
|
||||
if (p.s.bgColor && p.s.bgColor.theme) {
|
||||
p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
|
||||
if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
|
||||
}
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
}
|
||||
/* 18.3 Worksheets */
|
||||
function parse_ws_xml(data, opts, rels) {
|
||||
if(!data) return data;
|
||||
@ -2504,6 +2482,27 @@ function parse_ws_xml(data, opts, rels) {
|
||||
});
|
||||
}
|
||||
|
||||
/* 18.3.1.17 cols CT_Cols */
|
||||
var columns = [];
|
||||
if(opts.cellStyles && data.match(/<\/cols>/)) {
|
||||
/* 18.3.1.13 col CT_Col */
|
||||
var cols = data.match(/<col[^>]*\/>/g);
|
||||
var seencol = false;
|
||||
for(var coli = 0; coli != cols.length; ++coli) {
|
||||
var coll = parsexmltag(cols[coli]);
|
||||
delete coll[0];
|
||||
var colm=Number(coll.min)-1, colM=Number(coll.max)-1;
|
||||
delete coll.min, coll.max;
|
||||
if(!seencol && coll.width) { seencol = true; find_mdw(+coll.width, coll); }
|
||||
if(coll.width) {
|
||||
coll.wpx = width2px(+coll.width);
|
||||
coll.wch = px2char(coll.wpx);
|
||||
coll.MDW = MDW;
|
||||
}
|
||||
while(colm <= colM) columns[colm++] = coll;
|
||||
}
|
||||
}
|
||||
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var sidx = 0;
|
||||
|
||||
@ -2521,7 +2520,8 @@ function parse_ws_xml(data, opts, rels) {
|
||||
if(refguess.e.r < row.r - 1) refguess.e.r = row.r - 1;
|
||||
/* 18.3.1.4 c CT_Cell */
|
||||
var cells = x.substr(x.indexOf('>')+1).split(/<(?:\w+:)?c /);
|
||||
for(var ix = 0, c=cells[0]; ix != cells.length; ++ix,c=cells[ix]) {
|
||||
for(var ix = 0, c=cells[0]; ix != cells.length; ++ix) {
|
||||
c = cells[ix];
|
||||
if(c === "" || c.trim() === "") continue;
|
||||
var cref = c.match(/r=["']([^"']*)["']/), idx = ix;
|
||||
c = "<c " + c;
|
||||
@ -2572,21 +2572,9 @@ function parse_ws_xml(data, opts, rels) {
|
||||
if(cf && cf.numFmtId) fmtid = cf.numFmtId;
|
||||
if(opts.cellStyles && cf && cf.fillId) fillid = cf.fillId;
|
||||
}
|
||||
try {
|
||||
p.w = SSF.format(fmtid,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[fmtid];
|
||||
if(fillid) {
|
||||
p.s = styles.Fills[fillid];
|
||||
if (p.s.fgColor && p.s.fgColor.theme) {
|
||||
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
|
||||
}
|
||||
if (p.s.bgColor && p.s.bgColor.theme) {
|
||||
p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
|
||||
}
|
||||
}
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
safe_format(p, fmtid, fillid, opts);
|
||||
s[cell.r] = p;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* 18.3.1.48 hyperlinks CT_Hyperlinks */
|
||||
@ -2621,9 +2609,11 @@ function parse_ws_xml(data, opts, rels) {
|
||||
}
|
||||
}
|
||||
if(mergecells.length > 0) s["!merges"] = mergecells;
|
||||
if(columns.length > 0) s["!cols"] = columns;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
var WS_XML_ROOT = writextag('worksheet', null, {
|
||||
'xmlns': XMLNS.main[0],
|
||||
'xmlns:r': XMLNS.r
|
||||
@ -2663,12 +2653,28 @@ var write_ws_xml_data = function(ws, opts, idx, wb) {
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
var write_ws_cols = function(ws, cols) {
|
||||
var o = ["<cols>"], col, width;
|
||||
for(var i = 0; i != cols.length; ++i) {
|
||||
if(!(col = cols[i])) continue;
|
||||
var p = {min:i+1,max:i+1};
|
||||
/* wch (chars), wpx (pixels) */
|
||||
width = -1;
|
||||
if(col.wpx) width = px2char(col.wpx);
|
||||
else if(col.wch) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth= 1; }
|
||||
o.push(writextag('col', null, p));
|
||||
}
|
||||
o.push("</cols>");
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
var write_ws_xml = function(idx, opts, wb) {
|
||||
var o = [], s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}, sidx = 0, rdata = "";
|
||||
o.push(XML_HEADER);
|
||||
o.push(WS_XML_ROOT);
|
||||
o.push(writextag('dimension', null, {'ref': ws['!ref'] || 'A1'}));
|
||||
|
||||
if((ws['!cols']||[]).length > 0) o.push(write_ws_cols(ws, ws['!cols']));
|
||||
sidx = o.length;
|
||||
o.push(writextag('sheetData', null));
|
||||
if(ws['!ref']) rdata = write_ws_xml_data(ws, opts, idx, wb);
|
||||
@ -2856,10 +2862,7 @@ var parse_ws_bin = function(data, opts, rels) {
|
||||
case 'str': p.v = utf8read(val[1]); break;
|
||||
}
|
||||
if(opts.cellFormula && val.length > 3) p.f = val[3];
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) try {
|
||||
p.w = SSF.format(cf.ifmt,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[cf.ifmt];
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
|
||||
s[encode_cell({c:val[0].c,r:row.r})] = p;
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > val[0].c) refguess.s.c = val[0].c;
|
||||
@ -3277,14 +3280,16 @@ var WB_XML_ROOT = writextag('workbook', null, {
|
||||
'xmlns:r': XMLNS.r
|
||||
});
|
||||
|
||||
function safe1904(wb) {
|
||||
/* TODO: store date1904 somewhere else */
|
||||
try { return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { return "false"; }
|
||||
}
|
||||
|
||||
var write_wb_xml = function(wb, opts) {
|
||||
var o = [];
|
||||
o.push(XML_HEADER);
|
||||
o.push(WB_XML_ROOT);
|
||||
/* TODO: put this somewhere else */
|
||||
var date1904 = "false";
|
||||
try { date1904 = parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { date1904 = "false"; }
|
||||
o.push(writextag('workbookPr', null, {date1904:date1904}));
|
||||
o.push(writextag('workbookPr', null, {date1904:safe1904(wb)}));
|
||||
o.push("<sheets>");
|
||||
var i = 1;
|
||||
wb.SheetNames.forEach(function(s) {
|
||||
|
6
dist/xlsx.min.js
vendored
6
dist/xlsx.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.min.map
vendored
2
dist/xlsx.min.map
vendored
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.7.4",
|
||||
"version": "0.7.5",
|
||||
"author": "sheetjs",
|
||||
"description": "XLSB/XLSX/XLSM (Excel 2007+ Spreadsheet) parser and writer",
|
||||
"keywords": [ "xlsx", "xlsb", "xlsm", "office", "excel", "spreadsheet" ],
|
||||
@ -10,7 +10,7 @@
|
||||
"main": "./xlsx",
|
||||
"dependencies": {
|
||||
"ssf":"~0.7.0",
|
||||
"codepage":"1.x",
|
||||
"codepage":"~1.2.0",
|
||||
"cfb":">=0.9.1",
|
||||
"jszip":"2.2.2",
|
||||
"commander":""
|
||||
|
40
test.js
40
test.js
@ -560,7 +560,7 @@ describe('parse features', function() {
|
||||
describe('should correctly handle styles', function() {
|
||||
var ws, rn, rn2;
|
||||
before(function() {
|
||||
ws=X.readFile(paths.css1, {cellStyles:true}).Sheets.Sheet1;
|
||||
ws=X.readFile(paths.css1, {cellStyles:true,WTF:1}).Sheets.Sheet1;
|
||||
rn = function(range) {
|
||||
var r = X.utils.decode_range(range);
|
||||
var out = [];
|
||||
@ -574,7 +574,33 @@ describe('parse features', function() {
|
||||
'A1:D1,F1:G1', 'A2:D2,F2:G2', /* rows */
|
||||
'A3:A10', 'B3:B10', 'E1:E10', 'F6:F8', /* cols */
|
||||
'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' } }
|
||||
];
|
||||
ranges.forEach(function(rng) {
|
||||
it(rng,function(){cmparr(rn2(rng).map(function(x){ return ws[x].s; }));});
|
||||
});
|
||||
@ -585,6 +611,16 @@ describe('parse features', function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
it('correct styles', function() {
|
||||
var styles = ranges.map(function(r) { return rn2(r)[0]}).map(function(r) { return ws[r].s});
|
||||
for(var i = 0; i != exp.length; ++i) {
|
||||
[
|
||||
"fgColor.theme","fgColor.raw_rgb",
|
||||
"bgColor.theme","bgColor.raw_rgb",
|
||||
"patternType"
|
||||
].forEach(function(k) { deepcmp(exp[i], styles[i], k, i + ":"+k); });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
367
xlsx.js
367
xlsx.js
@ -2,7 +2,7 @@
|
||||
/* vim: set ts=2: */
|
||||
var XLSX = {};
|
||||
(function(XLSX){
|
||||
XLSX.version = '0.7.4';
|
||||
XLSX.version = '0.7.5';
|
||||
var current_codepage = 1252, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
@ -655,11 +655,16 @@ function parsexmltag(tag) {
|
||||
var words = tag.split(/\s+/);
|
||||
var z = {'0': words[0]};
|
||||
if(words.length === 1) return z;
|
||||
(tag.match(attregexg) || []).map(function(x){
|
||||
var y=x.match(attregex);
|
||||
y[1] = y[1].replace(/xmlns:/,"xmlns");
|
||||
z[y[1].replace(/^[a-zA-Z]*:/,"")] = y[2].substr(1,y[2].length-2);
|
||||
});
|
||||
var m = tag.match(attregexg), y, j, w, i;
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
y = m[i].match(attregex);
|
||||
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].substr(1,y[2].length-2);
|
||||
else {
|
||||
if(y[1].substr(0,6) === "xmlns:") w = "xmlns"+y[1].substr(6);
|
||||
else w = y[1].substr(j+1);
|
||||
z[w] = y[2].substr(1,y[2].length-2);
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
@ -676,7 +681,7 @@ var rencstr = "&<>'\"".split("");
|
||||
// TODO: CP remap (need to read file version to determine OS)
|
||||
function unescapexml(text){
|
||||
var s = text + '';
|
||||
s = s.replace(/"/g, '"').replace(/'/g, "'").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
||||
s = s.replace(/&[a-z]*;/g, function($$) { return encodings[$$]; });
|
||||
return s.replace(/_x([0-9a-fA-F]*)_/g,function(m,c) {return _chr(parseInt(c,16));});
|
||||
}
|
||||
function escapexml(text){
|
||||
@ -1825,6 +1830,67 @@ var parse_sst_bin = function(data, opts) {
|
||||
};
|
||||
|
||||
var write_sst_bin = function(sst, opts) { };
|
||||
var hex2RGB = function(h) {return h.substr(h[0]==="#"?1:0,6).match(/../g).map(function(x) { return parseInt(x,16); });};
|
||||
var rgb2Hex = function(rgb) {
|
||||
for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
|
||||
return o.toString(16).toUpperCase().substr(1);
|
||||
};
|
||||
|
||||
var rgb2HSL = function(rgb) {
|
||||
var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
|
||||
var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
|
||||
if(C === 0) return [0, 0, R];
|
||||
|
||||
var H6 = 0, S = 0, L2 = (M + m);
|
||||
S = C / (L2 > 1 ? 2 - L2 : L2);
|
||||
switch(M){
|
||||
case R: H6 = ((G - B) / C + 6)%6; break;
|
||||
case G: H6 = ((B - R) / C + 2); break;
|
||||
case B: H6 = ((R - G) / C + 4); break;
|
||||
}
|
||||
return [H6 / 6, S, L2 / 2];
|
||||
};
|
||||
|
||||
var hsl2RGB = function(hsl){
|
||||
var H = hsl[0], S = hsl[1], L = hsl[2];
|
||||
var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
|
||||
var rgb = [m,m,m], h6 = 6*H;
|
||||
|
||||
var X;
|
||||
if(S !== 0) switch(h6|0) {
|
||||
case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
|
||||
case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
|
||||
case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
|
||||
case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
|
||||
case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
|
||||
case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
|
||||
}
|
||||
for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
|
||||
return rgb;
|
||||
};
|
||||
|
||||
/* 18.8.3 bgColor tint algorithm */
|
||||
function rgb_tint(hex, tint) {
|
||||
if(tint === 0) return hex;
|
||||
var hsl = rgb2HSL(hex2RGB(hex));
|
||||
if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
|
||||
else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
|
||||
return rgb2Hex(hsl2RGB(hsl));
|
||||
}
|
||||
|
||||
/* 18.3.1.13 width calculations */
|
||||
var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
|
||||
function width2px(width) { return (( width + ((128/MDW)|0)/256 )* MDW )|0; }
|
||||
function px2char(px) { return (((px - 5)/MDW * 100 + 0.5)|0)/100; }
|
||||
function char2width(chr) { return (((chr * MDW + 5)/MDW*256)|0)/256; }
|
||||
function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
|
||||
function find_mdw(collw, coll) {
|
||||
if(cycle_width(collw) != collw) {
|
||||
for(MDW=DEF_MDW; MDW>MIN_MDW; --MDW) if(cycle_width(collw) === collw) break;
|
||||
if(MDW === MIN_MDW) for(MDW=DEF_MDW+1; MDW<MAX_MDW; ++MDW) if(cycle_width(collw) === collw) break;
|
||||
if(MDW === MAX_MDW) MDW = DEF_MDW;
|
||||
}
|
||||
}
|
||||
var styles = {}; // shared styles
|
||||
|
||||
var themes = {}; // shared themes
|
||||
@ -2111,113 +2177,7 @@ function parse_sty_bin(data, opts) {
|
||||
function write_sty_bin(data, opts) { }
|
||||
RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
||||
|
||||
/* Various RGB/HSL utility functions - might want to put these elsewhere. */
|
||||
/* From http://www.javascripter.net/faq/hextorgb.htm, usage: var X = hexToX('FFFFFF') */
|
||||
function cutHex(h) {return (h.charAt(0)=="#") ? h.substring(1,7):h}
|
||||
function hexToR(h) {return parseInt((cutHex(h)).substring(0,2),16)}
|
||||
function hexToG(h) {return parseInt((cutHex(h)).substring(2,4),16)}
|
||||
function hexToB(h) {return parseInt((cutHex(h)).substring(4,6),16)}
|
||||
/* From http://www.javascripter.net/faq/rgbtohex.htm, usage: var RGB = rgbToHex(R, G, B) */
|
||||
function toHex(n) {
|
||||
n = parseInt(n,10);
|
||||
if (isNaN(n)) return "00";
|
||||
n = Math.max(0,Math.min(n,255));
|
||||
return "0123456789ABCDEF".charAt((n-n%16)/16)
|
||||
+ "0123456789ABCDEF".charAt(n%16);
|
||||
}
|
||||
function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)}
|
||||
/* From the specification. */
|
||||
var HLSMAX = 255;
|
||||
/* From https://gist.github.com/mjackson/5311256 via http://stackoverflow.com/a/9493060 */
|
||||
/**
|
||||
* Converts an RGB color value to HSL. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes r, g, and b are contained in the set [0, 255] and
|
||||
* returns h, s, and l in the set [0, 1].
|
||||
*
|
||||
* @param Number r The red color value
|
||||
* @param Number g The green color value
|
||||
* @param Number b The blue color value
|
||||
* @return Array The HSL representation
|
||||
*/
|
||||
function rgbToHsl(r, g, b){
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if(max == min){
|
||||
h = s = 0; // achromatic
|
||||
}else{
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch(max){
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
case b: h = (r - g) / d + 4; break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [h, s, l];
|
||||
}
|
||||
/**
|
||||
* Converts an HSL color value to RGB. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||
* returns r, g, and b in the set [0, 255].
|
||||
*
|
||||
* @param Number h The hue
|
||||
* @param Number s The saturation
|
||||
* @param Number l The lightness
|
||||
* @return Array The RGB representation
|
||||
*/
|
||||
function hslToRgb(h, s, l){
|
||||
var r, g, b;
|
||||
|
||||
if(s == 0){
|
||||
r = g = b = l; // achromatic
|
||||
}else{
|
||||
function hue2rgb(p, q, t){
|
||||
if(t < 0) t += 1;
|
||||
if(t > 1) t -= 1;
|
||||
if(t < 1/6) return p + (q - p) * 6 * t;
|
||||
if(t < 1/2) return q;
|
||||
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
var p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
||||
}
|
||||
/* Utility function to apply tint to an RGB color. */
|
||||
function rgb_tint(rgb, tint) {
|
||||
var r = hexToR(rgb),
|
||||
g = hexToG(rgb),
|
||||
b = hexToB(rgb),
|
||||
hsl = rgbToHsl(r, g, b);
|
||||
|
||||
/* Apply tint as described in pages 1757-1758 of the ECMA Office Open XML specification. */
|
||||
/* NOTE: This is totally messed up... see http://social.msdn.microsoft.com/Forums/en-US/e9d8c136-6d62-4098-9b1b-dac786149f43/excel-color-tint-algorithm-incorrect */
|
||||
if (tint < 0) {
|
||||
hsl[2] = hsl[2] * (1.0 + tint);
|
||||
} else if (tint > 0) {
|
||||
hsl[2] = hsl[2] * (1.0 + tint);
|
||||
|
||||
// XXX This doesn't work...
|
||||
//hsl[2] = hsl[2] * (1.0 - tint) + (HLSMAX - HLSMAX * (1.0 - tint));
|
||||
}
|
||||
|
||||
rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
|
||||
|
||||
return rgbToHex(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
/* 20.1.6.2 clrScheme CT_ColorScheme */
|
||||
function parse_clrScheme(t, opts) {
|
||||
themes.themeElements.clrScheme = [];
|
||||
var color = {};
|
||||
@ -2287,7 +2247,7 @@ function parse_theme_xml(data, opts) {
|
||||
|
||||
var t;
|
||||
|
||||
/* clrScheme */
|
||||
/* clrScheme CT_ColorScheme */
|
||||
if((t=data.match(/<a:clrScheme([^>]*)>.*<\/a:clrScheme>/))) parse_clrScheme(t, opts);
|
||||
|
||||
return themes;
|
||||
@ -2342,6 +2302,48 @@ function parse_cc_bin(data, opts) {
|
||||
}
|
||||
|
||||
function write_cc_bin(data, opts) { }
|
||||
|
||||
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
|
||||
for(var i = 0; i != dirComments.length; ++i) {
|
||||
var canonicalpath=dirComments[i];
|
||||
var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
|
||||
if(!comments || !comments.length) continue;
|
||||
// find the sheets targeted by these comments
|
||||
var sheetNames = keys(sheets);
|
||||
for(var j = 0; j != sheetNames.length; ++j) {
|
||||
var sheetName = sheetNames[j];
|
||||
var rels = sheetRels[sheetName];
|
||||
if(rels) {
|
||||
var rel = rels[canonicalpath];
|
||||
if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertCommentsIntoSheet(sheetName, sheet, comments) {
|
||||
comments.forEach(function(comment) {
|
||||
var cell = sheet[comment.ref];
|
||||
if (!cell) {
|
||||
cell = {};
|
||||
sheet[comment.ref] = cell;
|
||||
var range = decode_range(sheet["!ref"]||"BDWGO1000001:A1");
|
||||
var thisCell = decode_cell(comment.ref);
|
||||
if(range.s.r > thisCell.r) range.s.r = thisCell.r;
|
||||
if(range.e.r < thisCell.r) range.e.r = thisCell.r;
|
||||
if(range.s.c > thisCell.c) range.s.c = thisCell.c;
|
||||
if(range.e.c < thisCell.c) range.e.c = thisCell.c;
|
||||
var encoded = encode_range(range);
|
||||
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
|
||||
}
|
||||
|
||||
if (!cell.c) cell.c = [];
|
||||
var o = {a: comment.author, t: comment.t, r: comment.r};
|
||||
if(comment.h) o.h = comment.h;
|
||||
cell.c.push(o);
|
||||
});
|
||||
}
|
||||
|
||||
/* 18.7.3 CT_Comment */
|
||||
function parse_comments_xml(data, opts) {
|
||||
if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
|
||||
@ -2415,48 +2417,6 @@ function parse_comments_bin(data, opts) {
|
||||
}
|
||||
|
||||
function write_comments_bin(data, opts) { }
|
||||
|
||||
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
|
||||
for(var i = 0; i != dirComments.length; ++i) {
|
||||
var canonicalpath=dirComments[i];
|
||||
var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
|
||||
if(!comments || !comments.length) continue;
|
||||
// find the sheets targeted by these comments
|
||||
var sheetNames = keys(sheets);
|
||||
for(var j = 0; j != sheetNames.length; ++j) {
|
||||
var sheetName = sheetNames[j];
|
||||
var rels = sheetRels[sheetName];
|
||||
if(rels) {
|
||||
var rel = rels[canonicalpath];
|
||||
if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function insertCommentsIntoSheet(sheetName, sheet, comments) {
|
||||
comments.forEach(function(comment) {
|
||||
var cell = sheet[comment.ref];
|
||||
if (!cell) {
|
||||
cell = {};
|
||||
sheet[comment.ref] = cell;
|
||||
var range = decode_range(sheet["!ref"]||"BDWGO1000001:A1");
|
||||
var thisCell = decode_cell(comment.ref);
|
||||
if(range.s.r > thisCell.r) range.s.r = thisCell.r;
|
||||
if(range.e.r < thisCell.r) range.e.r = thisCell.r;
|
||||
if(range.s.c > thisCell.c) range.s.c = thisCell.c;
|
||||
if(range.e.c < thisCell.c) range.e.c = thisCell.c;
|
||||
var encoded = encode_range(range);
|
||||
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
|
||||
}
|
||||
|
||||
if (!cell.c) cell.c = [];
|
||||
var o = {a: comment.author, t: comment.t, r: comment.r};
|
||||
if(comment.h) o.h = comment.h;
|
||||
cell.c.push(o);
|
||||
});
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.5.97.4 CellParsedFormula TODO: use similar logic to js-xls */
|
||||
var parse_CellParsedFormula = function(data, length) {
|
||||
var cce = data.read_shift(4);
|
||||
@ -2485,6 +2445,24 @@ function get_cell_style(styles, cell, opts) {
|
||||
};
|
||||
return styles.length-1;
|
||||
}
|
||||
|
||||
function safe_format(p, fmtid, fillid, opts) {
|
||||
try {
|
||||
p.w = SSF.format(fmtid,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[fmtid];
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
if(fillid) try {
|
||||
p.s = styles.Fills[fillid];
|
||||
if (p.s.fgColor && p.s.fgColor.theme) {
|
||||
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
|
||||
if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
|
||||
}
|
||||
if (p.s.bgColor && p.s.bgColor.theme) {
|
||||
p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
|
||||
if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
|
||||
}
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
}
|
||||
/* 18.3 Worksheets */
|
||||
function parse_ws_xml(data, opts, rels) {
|
||||
if(!data) return data;
|
||||
@ -2504,6 +2482,27 @@ function parse_ws_xml(data, opts, rels) {
|
||||
});
|
||||
}
|
||||
|
||||
/* 18.3.1.17 cols CT_Cols */
|
||||
var columns = [];
|
||||
if(opts.cellStyles && data.match(/<\/cols>/)) {
|
||||
/* 18.3.1.13 col CT_Col */
|
||||
var cols = data.match(/<col[^>]*\/>/g);
|
||||
var seencol = false;
|
||||
for(var coli = 0; coli != cols.length; ++coli) {
|
||||
var coll = parsexmltag(cols[coli]);
|
||||
delete coll[0];
|
||||
var colm=Number(coll.min)-1, colM=Number(coll.max)-1;
|
||||
delete coll.min, coll.max;
|
||||
if(!seencol && coll.width) { seencol = true; find_mdw(+coll.width, coll); }
|
||||
if(coll.width) {
|
||||
coll.wpx = width2px(+coll.width);
|
||||
coll.wch = px2char(coll.wpx);
|
||||
coll.MDW = MDW;
|
||||
}
|
||||
while(colm <= colM) columns[colm++] = coll;
|
||||
}
|
||||
}
|
||||
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var sidx = 0;
|
||||
|
||||
@ -2521,7 +2520,8 @@ function parse_ws_xml(data, opts, rels) {
|
||||
if(refguess.e.r < row.r - 1) refguess.e.r = row.r - 1;
|
||||
/* 18.3.1.4 c CT_Cell */
|
||||
var cells = x.substr(x.indexOf('>')+1).split(/<(?:\w+:)?c /);
|
||||
for(var ix = 0, c=cells[0]; ix != cells.length; ++ix,c=cells[ix]) {
|
||||
for(var ix = 0, c=cells[0]; ix != cells.length; ++ix) {
|
||||
c = cells[ix];
|
||||
if(c === "" || c.trim() === "") continue;
|
||||
var cref = c.match(/r=["']([^"']*)["']/), idx = ix;
|
||||
c = "<c " + c;
|
||||
@ -2572,21 +2572,9 @@ function parse_ws_xml(data, opts, rels) {
|
||||
if(cf && cf.numFmtId) fmtid = cf.numFmtId;
|
||||
if(opts.cellStyles && cf && cf.fillId) fillid = cf.fillId;
|
||||
}
|
||||
try {
|
||||
p.w = SSF.format(fmtid,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[fmtid];
|
||||
if(fillid) {
|
||||
p.s = styles.Fills[fillid];
|
||||
if (p.s.fgColor && p.s.fgColor.theme) {
|
||||
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
|
||||
}
|
||||
if (p.s.bgColor && p.s.bgColor.theme) {
|
||||
p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
|
||||
}
|
||||
}
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
safe_format(p, fmtid, fillid, opts);
|
||||
s[cell.r] = p;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* 18.3.1.48 hyperlinks CT_Hyperlinks */
|
||||
@ -2621,9 +2609,11 @@ function parse_ws_xml(data, opts, rels) {
|
||||
}
|
||||
}
|
||||
if(mergecells.length > 0) s["!merges"] = mergecells;
|
||||
if(columns.length > 0) s["!cols"] = columns;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
var WS_XML_ROOT = writextag('worksheet', null, {
|
||||
'xmlns': XMLNS.main[0],
|
||||
'xmlns:r': XMLNS.r
|
||||
@ -2663,12 +2653,28 @@ var write_ws_xml_data = function(ws, opts, idx, wb) {
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
var write_ws_cols = function(ws, cols) {
|
||||
var o = ["<cols>"], col, width;
|
||||
for(var i = 0; i != cols.length; ++i) {
|
||||
if(!(col = cols[i])) continue;
|
||||
var p = {min:i+1,max:i+1};
|
||||
/* wch (chars), wpx (pixels) */
|
||||
width = -1;
|
||||
if(col.wpx) width = px2char(col.wpx);
|
||||
else if(col.wch) width = col.wch;
|
||||
if(width > -1) { p.width = char2width(width); p.customWidth= 1; }
|
||||
o.push(writextag('col', null, p));
|
||||
}
|
||||
o.push("</cols>");
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
var write_ws_xml = function(idx, opts, wb) {
|
||||
var o = [], s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}, sidx = 0, rdata = "";
|
||||
o.push(XML_HEADER);
|
||||
o.push(WS_XML_ROOT);
|
||||
o.push(writextag('dimension', null, {'ref': ws['!ref'] || 'A1'}));
|
||||
|
||||
if((ws['!cols']||[]).length > 0) o.push(write_ws_cols(ws, ws['!cols']));
|
||||
sidx = o.length;
|
||||
o.push(writextag('sheetData', null));
|
||||
if(ws['!ref']) rdata = write_ws_xml_data(ws, opts, idx, wb);
|
||||
@ -2856,10 +2862,7 @@ var parse_ws_bin = function(data, opts, rels) {
|
||||
case 'str': p.v = utf8read(val[1]); break;
|
||||
}
|
||||
if(opts.cellFormula && val.length > 3) p.f = val[3];
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) try {
|
||||
p.w = SSF.format(cf.ifmt,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[cf.ifmt];
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
|
||||
s[encode_cell({c:val[0].c,r:row.r})] = p;
|
||||
if(refguess.s.r > row.r) refguess.s.r = row.r;
|
||||
if(refguess.s.c > val[0].c) refguess.s.c = val[0].c;
|
||||
@ -3277,14 +3280,16 @@ var WB_XML_ROOT = writextag('workbook', null, {
|
||||
'xmlns:r': XMLNS.r
|
||||
});
|
||||
|
||||
function safe1904(wb) {
|
||||
/* TODO: store date1904 somewhere else */
|
||||
try { return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { return "false"; }
|
||||
}
|
||||
|
||||
var write_wb_xml = function(wb, opts) {
|
||||
var o = [];
|
||||
o.push(XML_HEADER);
|
||||
o.push(WB_XML_ROOT);
|
||||
/* TODO: put this somewhere else */
|
||||
var date1904 = "false";
|
||||
try { date1904 = parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { date1904 = "false"; }
|
||||
o.push(writextag('workbookPr', null, {date1904:date1904}));
|
||||
o.push(writextag('workbookPr', null, {date1904:safe1904(wb)}));
|
||||
o.push("<sheets>");
|
||||
var i = 1;
|
||||
wb.SheetNames.forEach(function(s) {
|
||||
|
Loading…
Reference in New Issue
Block a user