って要件があって、ちょっと書いてみた。
jQuery使ってるサイトに使う予定だったのでjQuery.mapとか使って書いてたけど、なんかうまく配列を作れなかったのでライブラリ非依存な感じにしてみた。
古めなサイトに使う用なので、トランスパイルもしない方針で書いた。ArrowFunctionは使っても良かったかもなぁ・・・
Table2CSV.js
var Table2CSV = function($table, tbodyTrSelector, theadTrSelector) {
var __map = Array.prototype.map;
var strToCSVStr = function(str) {
return '"' + str.replace(/"/g, '""') + '"';
}
var convertToCSVValue = function(str) {
if (str.match(/^-?[\d]+$/)) {
return parseInt(str);
} else if (str.match(/^-?[\d]+\.[\d]+$/)) {
return parseFloat(str);
} else {
return strToCSVStr(str);
}
}
var convertToText = function(elem) {
var text = $(elem).text();
text = text.replace(/\\|¥|,|%/g, '').trim();
return convertToCSVValue(text);
}
var mapIt = function(baseElem, selector, converter) {
var mapped = __map.call(baseElem.querySelectorAll(selector), function(e, i) {
var converted = converter ? converter(e) : e;
return converted;
});
return mapped;
}
var CSVJoin = function(arr) {
return arr.reduce(function(prev, v) {
prev.push(v.join(','));
return prev;
}, []).join("\n");
}
var $header = mapIt($table, theadTrSelector, function(e) {
return mapIt(e, 'th,td', convertToText);
})
var $body = mapIt($table, tbodyTrSelector, function(e) {
return mapIt(e, 'th,td', convertToText);
})
var csv = CSVJoin($header.concat($body));
var dl = function(name, content, withBOM) {
content = content || this.csv;
withBOM = (typeof(withBOM) === 'boolean') ? withBOM : true;
var bom = withBOM ? new Uint8Array([0xEF, 0xBB, 0xBF]) : '';
var blob = new Blob([bom, content], { type: 'application/csv;charset=utf8'});
var a = [
['href', window.URL.createObjectURL(blob)],
['download', name]
].reduce(function(_a, attr) {
_a.setAttribute(attr[0], attr[1]);
return _a;
} ,document.createElement('a'));
var clickEvent = new MouseEvent('click');
a.dispatchEvent(clickEvent);
}
return {
csv: csv,
dl: dl
}
}
Table2CSV.getTableNode = function(selector, index) {
index = index || 0;
return document.querySelectorAll(selector).item(index);
}
/*
var t2c = new Table2CSV(Table2CSV.getTableNode('table'), 'tr');
t2c.dl('hoge.csv')
*/
DLのとこはIEでは動かなかったりするはず。
mapとかreduceとか使ってるけど最近のChromeとかFirefoxなら動くはず。動かなかったらpolyfillで対応できると思う。
追記
MacのChromeで試してみたらうまくクリックイベントが発火しなかったので FileSaver を参考にして MouseEvent
のインスタンスを作って渡すようにした。
before
var clickEvent = document.createEvent('HTMLEvents');
clickEvent.initEvent('click', true, true);
after
var clickEvent = new MouseEvent('click');
自宅の環境がLinuxMintだったからなのか、Chromeのバージョンが古かったのか、どっちかだと思う。あとはWindowsでちゃんと動いてくれればいいんだけど・・・