Skip to content

Instantly share code, notes, and snippets.

@erickzhao
Last active October 1, 2017 17:17
Show Gist options
  • Save erickzhao/a830925068890ad30533e13e51206194 to your computer and use it in GitHub Desktop.
Save erickzhao/a830925068890ad30533e13e51206194 to your computer and use it in GitHub Desktop.
requirebin sketch
let CSVExportService = require('json2csvexporter').default;
const exporter = CSVExportService.create();
function download(htmlTable) {
exporter.downloadCSV(tableToJson(htmlTable));
}
// Credits: http://johndyer.name/html-table-to-json/
function tableToJson(table) {
let data = []; // first row needs to be headers
var headers = [];
for (var i=0; i<table.rows[0].cells.length; i++) {
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi,'');
}
// go through cells
for (var i=1; i<table.rows.length; i++) {
var tableRow = table.rows[i]; var rowData = {};
for (var j=0; j<tableRow.cells.length; j++) {
rowData[ headers[j] ] = tableRow.cells[j].innerHTML;
}
data.push(rowData);
}
return data;
}
const table = document.querySelector('#data-table');
const button = document.querySelector('#dl-btn');
button.addEventListener('click', () => download(document.querySelector('#data-table')));
setTimeout(function(){
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Provides an interface for maping JS datatypes to a delimiter-seperated value.
* Creates a list of lists called rows and maps it to a Blob via toBlob().
*/
var WriterService = function () {
/**
* Default constructors. Takes two optional params.
* @param {String} delimiter - Delimitercharacter(s) to be used in the CSV.
* @param {String} contentType - Type of file.
*/
function WriterService() {
var delimiter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ',';
var contentType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text/csv';
_classCallCheck(this, WriterService);
this.delimiter = delimiter;
this.contentType = contentType;
this.rows = [[]];
}
/**
* Returns the current row
* @return {Array} - An array of values.
*/
_createClass(WriterService, [{
key: 'wrapWithQuotes',
/**
* Returns the input string
* @param {String} string - The input string.
* @return {String} - A safe strings wrapped in quotes.
*/
value: function wrapWithQuotes(string) {
var safeString = string.replace(/"/g, '""');
return '"' + safeString + '"';
}
/**
* Pushes a new value into the current row.
* @param {Any} value - The value to push.
*/
}, {
key: 'writeValue',
value: function writeValue(value) {
var stringValue = value === undefined ? '' : String(value);
var needsQuotes = stringValue.indexOf(this.delimiter) !== -1 || /"\r\n/.test(stringValue);
this.currentRow.push(needsQuotes ? this.wrapWithQuotes(stringValue) : stringValue);
}
/**
* Adds a en empty array to rows property. This maps to an empty line.
*/
}, {
key: 'writeLine',
value: function writeLine() {
this.rows.push([]);
}
/**
* Flatten rows to a String.
* @return {String} - A string representation of the rows..
*/
}, {
key: 'toString',
value: function toString() {
var _this = this;
return this.rows.map(function (row) {
return row.join(_this.delimiter);
}).reduce(function (content, row) {
return content + '\r\n' + row;
});
}
/**
* Transform the rows into a Blob.
* @return {Object} - A representation of the rows in the form of a Blob. The returned Object is an instance of Blob, but typeof Object.
*/
}, {
key: 'toBlob',
value: function toBlob() {
return new Blob([this.toString()], { type: this.contentType });
}
}, {
key: 'currentRow',
get: function get() {
return this.rows[this.rows.length - 1];
}
}]);
return WriterService;
}();
exports.default = WriterService;
},{}],"json2csvexporter":[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _WriterService = require('./WriterService');
var _WriterService2 = _interopRequireDefault(_WriterService);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Provides an ExportService that uses WriterService to mentain an in-memory representation of the CSV file.
* Uses downloadCSV to map the [data] via the Writer to a Blob and initiate download which triggers the download of the actual file in the browser.
* Provides static methods for Singleton-like usage.
*/
var CSVExportService = function () {
/**
* Default constructor. Takes an optional options param.
* @param {Object} options - Provides the configuration options.
*/
function CSVExportService(options) {
_classCallCheck(this, CSVExportService);
this.options = options || {};
}
/**
* Shorthand for createCSV() with a pre-set writerType
*/
_createClass(CSVExportService, [{
key: 'createCSVBlob',
value: function createCSVBlob(data) {
return this.createCSV(data);
}
/**
* Shorthand for createCSV() with a pre-set writerType
*/
}, {
key: 'dataToString',
value: function dataToString(data) {
return this.createCSV(data, 'string');
}
/**
* Creates a Blob based on the provided data and configuration options.
* @param {Array} data - An array of JSON objects that will be mapped to the Blob.
* @param {String} writerType - ENUM for choosing the return type. Default to 'blo'
* @return {Object|String} - The Blob object (Is an instance of Blob, but typeof Object) or a String version of the CSV with newlines.
*/
}, {
key: 'createCSV',
value: function createCSV(data) {
var writerType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'blob';
var _ref = this.options || {},
optionsColumns = _ref.columns,
optionsContentType = _ref.contentType,
optionsDelimeter = _ref.delimeter,
optionsDelimiter = _ref.delimiter,
optionsFormatters = _ref.formatters,
optionsHeaders = _ref.headers,
optionsIncludeHeaders = _ref.includeHeaders;
var contentType = optionsContentType || 'text/csv';
var delimiter = optionsDelimeter || ',';
var formatters = optionsFormatters || {};
var getFormater = function getFormater(header) {
return formatters[header] || function (v) {
return v;
};
};
var headerNames = optionsHeaders || {};
var headers = optionsColumns || Object.getOwnPropertyNames(data[0]);
var includeHeaders = optionsIncludeHeaders;
var writer = new _WriterService2.default(delimiter, contentType);
if (includeHeaders === undefined || includeHeaders) {
headers.forEach(function (header) {
return writer.writeValue(headerNames[header] || header);
});
writer.writeLine();
}
data.forEach(function (row) {
headers.forEach(function (header) {
return writer.writeValue(getFormater(header)(row[header]));
});
writer.writeLine();
});
return writerType === 'string' ? writer.toString() : writer.toBlob();
}
/**
* Triggers the download of the file.
* @param {Object} blob - The blob to be downloaded.
* @param {String} filename - Name of the file.
*/
}, {
key: 'download',
value: function download(blob, filename) {
if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, filename);
return;
}
var link = document.createElement('A');
var url = URL.createObjectURL(blob);
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
/**
* Creates and passes the blob and filename params to the download() method. In case of error, calls the onError callback (if provided) and prints a error mesage if devMode is enabled via options.
* @param {Array} data - An array of objects to map and store.
*/
}, {
key: 'downloadCSV',
value: function downloadCSV(data) {
try {
var blob = this.createCSV(data, 'blob');
var filename = this.options.filename || 'export-' + (new Date().getTime() / 1000 | 0) + '.csv';
this.download(blob, filename);
} catch (err) {
if (this.options.devMode) {
console.error('Error downloading CSV. Send this log to the developers: \n', err);
}
if (this.options.onError) {
this.options.onError(err);
}
}
}
}, {
key: 'toString',
value: function toString(data) {
var writer = new _WriterService2.default(delimiter, contentType);
}
/**
* Shorthand for constructor.
* @param {Object} options
* @return {Object} - An instance of CSVExportService
*/
}], [{
key: 'create',
value: function create(options) {
return new CSVExportService(options);
}
/**
* Shorthand for initialization and download() call.
* @param {Array} data - An array of objects to map and store.
* @return {undefined}
*/
}, {
key: 'download',
value: function download(data) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new CSVExportService(options).downloadCSV(data);
}
}]);
return CSVExportService;
}();
exports.default = CSVExportService;
},{"./WriterService":1}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImxpYi9Xcml0ZXJTZXJ2aWNlLmpzIiwianNvbjJjc3ZleHBvcnRlciJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuXG52YXIgX2NyZWF0ZUNsYXNzID0gZnVuY3Rpb24gKCkgeyBmdW5jdGlvbiBkZWZpbmVQcm9wZXJ0aWVzKHRhcmdldCwgcHJvcHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykgeyB2YXIgZGVzY3JpcHRvciA9IHByb3BzW2ldOyBkZXNjcmlwdG9yLmVudW1lcmFibGUgPSBkZXNjcmlwdG9yLmVudW1lcmFibGUgfHwgZmFsc2U7IGRlc2NyaXB0b3IuY29uZmlndXJhYmxlID0gdHJ1ZTsgaWYgKFwidmFsdWVcIiBpbiBkZXNjcmlwdG9yKSBkZXNjcmlwdG9yLndyaXRhYmxlID0gdHJ1ZTsgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgZGVzY3JpcHRvci5rZXksIGRlc2NyaXB0b3IpOyB9IH0gcmV0dXJuIGZ1bmN0aW9uIChDb25zdHJ1Y3RvciwgcHJvdG9Qcm9wcywgc3RhdGljUHJvcHMpIHsgaWYgKHByb3RvUHJvcHMpIGRlZmluZVByb3BlcnRpZXMoQ29uc3RydWN0b3IucHJvdG90eXBlLCBwcm90b1Byb3BzKTsgaWYgKHN0YXRpY1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLCBzdGF0aWNQcm9wcyk7IHJldHVybiBDb25zdHJ1Y3RvcjsgfTsgfSgpO1xuXG5mdW5jdGlvbiBfY2xhc3NDYWxsQ2hlY2soaW5zdGFuY2UsIENvbnN0cnVjdG9yKSB7IGlmICghKGluc3RhbmNlIGluc3RhbmNlb2YgQ29uc3RydWN0b3IpKSB7IHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb25cIik7IH0gfVxuXG4vKipcbiAqIFByb3ZpZGVzIGFuIGludGVyZmFjZSBmb3IgbWFwaW5nIEpTIGRhdGF0eXBlcyB0byBhIGRlbGltaXRlci1zZXBlcmF0ZWQgdmFsdWUuXG4gKiBDcmVhdGVzIGEgbGlzdCBvZiBsaXN0cyBjYWxsZWQgcm93cyBhbmQgbWFwcyBpdCB0byBhIEJsb2IgdmlhIHRvQmxvYigpLlxuICovXG52YXIgV3JpdGVyU2VydmljZSA9IGZ1bmN0aW9uICgpIHtcbiAgLyoqXG4gICAqIERlZmF1bHQgY29uc3RydWN0b3JzLiBUYWtlcyB0d28gb3B0aW9uYWwgcGFyYW1zLlxuICAgKiBAcGFyYW0gIHtTdHJpbmd9IGRlbGltaXRlciAtIERlbGltaXRlcmNoYXJhY3RlcihzKSB0byBiZSB1c2VkIGluIHRoZSBDU1YuXG4gICAqIEBwYXJhbSAge1N0cmluZ30gY29udGVudFR5cGUgLSBUeXBlIG9mIGZpbGUuXG4gICAqL1xuICBmdW5jdGlvbiBXcml0ZXJTZXJ2aWNlKCkge1xuICAgIHZhciBkZWxpbWl0ZXIgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6ICcsJztcbiAgICB2YXIgY29udGVudFR5cGUgPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6ICd0ZXh0L2Nzdic7XG5cbiAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgV3JpdGVyU2VydmljZSk7XG5cbiAgICB0aGlzLmRlbGltaXRlciA9IGRlbGltaXRlcjtcbiAgICB0aGlzLmNvbnRlbnRUeXBlID0gY29udGVudFR5cGU7XG4gICAgdGhpcy5yb3dzID0gW1tdXTtcbiAgfVxuICAvKipcbiAgICogUmV0dXJucyB0aGUgY3VycmVudCByb3dcbiAgICogQHJldHVybiB7QXJyYXl9IC0gQW4gYXJyYXkgb2YgdmFsdWVzLlxuICAgKi9cblxuXG4gIF9jcmVhdGVDbGFzcyhXcml0ZXJTZXJ2aWNlLCBbe1xuICAgIGtleTogJ3dyYXBXaXRoUXVvdGVzJyxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGlucHV0IHN0cmluZ1xuICAgICAqIEBwYXJhbSAge1N0cmluZ30gc3RyaW5nIC0gVGhlIGlucHV0IHN0cmluZy5cbiAgICAgKiBAcmV0dXJuIHtTdHJpbmd9IC0gQSBzYWZlIHN0cmluZ3Mgd3JhcHBlZCBpbiBxdW90ZXMuXG4gICAgICovXG4gICAgdmFsdWU6IGZ1bmN0aW9uIHdyYXBXaXRoUXVvdGVzKHN0cmluZykge1xuICAgICAgdmFyIHNhZmVTdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvXCIvZywgJ1wiXCInKTtcbiAgICAgIHJldHVybiAnXCInICsgc2FmZVN0cmluZyArICdcIic7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFB1c2hlcyBhIG5ldyB2YWx1ZSBpbnRvIHRoZSBjdXJyZW50IHJvdy5cbiAgICAgKiBAcGFyYW0gIHtBbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIHB1c2guXG4gICAgICovXG5cbiAgfSwge1xuICAgIGtleTogJ3dyaXRlVmFsdWUnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiB3cml0ZVZhbHVlKHZhbHVlKSB7XG4gICAgICB2YXIgc3RyaW5nVmFsdWUgPSB2YWx1ZSA9PT0gdW5kZWZpbmVkID8gJycgOiBTdHJpbmcodmFsdWUpO1xuICAgICAgdmFyIG5lZWRzUXVvdGVzID0gc3RyaW5nVmFsdWUuaW5kZXhPZih0aGlzLmRlbGltaXRlcikgIT09IC0xIHx8IC9cIlxcclxcbi8udGVzdChzdHJpbmdWYWx1ZSk7XG4gICAgICB0aGlzLmN1cnJlbnRSb3cucHVzaChuZWVkc1F1b3RlcyA/IHRoaXMud3JhcFdpdGhRdW90ZXMoc3RyaW5nVmFsdWUpIDogc3RyaW5nVmFsdWUpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgZW4gZW1wdHkgYXJyYXkgdG8gcm93cyBwcm9wZXJ0eS4gVGhpcyBtYXBzIHRvIGFuIGVtcHR5IGxpbmUuXG4gICAgICovXG5cbiAgfSwge1xuICAgIGtleTogJ3dyaXRlTGluZScsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIHdyaXRlTGluZSgpIHtcbiAgICAgIHRoaXMucm93cy5wdXNoKFtdKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogRmxhdHRlbiByb3dzIHRvIGEgU3RyaW5nLlxuICAgICAqIEByZXR1cm4ge1N0cmluZ30gLSBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcm93cy4uXG4gICAgICovXG5cbiAgfSwge1xuICAgIGtleTogJ3RvU3RyaW5nJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICByZXR1cm4gdGhpcy5yb3dzLm1hcChmdW5jdGlvbiAocm93KSB7XG4gICAgICAgIHJldHVybiByb3cuam9pbihfdGhpcy5kZWxpbWl0ZXIpO1xuICAgICAgfSkucmVkdWNlKGZ1bmN0aW9uIChjb250ZW50LCByb3cpIHtcbiAgICAgICAgcmV0dXJuIGNvbnRlbnQgKyAnXFxyXFxuJyArIHJvdztcbiAgICAgIH0pO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBUcmFuc2Zvcm0gdGhlIHJvd3MgaW50byBhIEJsb2IuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSAtIEEgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJvd3MgaW4gdGhlIGZvcm0gb2YgYSBCbG9iLiBUaGUgcmV0dXJuZWQgT2JqZWN0IGlzIGFuIGluc3RhbmNlIG9mIEJsb2IsIGJ1dCB0eXBlb2YgT2JqZWN0LlxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICd0b0Jsb2InLFxuICAgIHZhbHVlOiBmdW5jdGlvbiB0b0Jsb2IoKSB7XG4gICAgICByZXR1cm4gbmV3IEJsb2IoW3RoaXMudG9TdHJpbmcoKV0sIHsgdHlwZTogdGhpcy5jb250ZW50VHlwZSB9KTtcbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdjdXJyZW50Um93JyxcbiAgICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICAgIHJldHVybiB0aGlzLnJvd3NbdGhpcy5yb3dzLmxlbmd0aCAtIDFdO1xuICAgIH1cbiAgfV0pO1xuXG4gIHJldHVybiBXcml0ZXJTZXJ2aWNlO1xufSgpO1xuXG5leHBvcnRzLmRlZmF1bHQgPSBXcml0ZXJTZXJ2aWNlOyIsIid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF9jcmVhdGVDbGFzcyA9IGZ1bmN0aW9uICgpIHsgZnVuY3Rpb24gZGVmaW5lUHJvcGVydGllcyh0YXJnZXQsIHByb3BzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHsgdmFyIGRlc2NyaXB0b3IgPSBwcm9wc1tpXTsgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlOyBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IHRydWU7IGlmIChcInZhbHVlXCIgaW4gZGVzY3JpcHRvcikgZGVzY3JpcHRvci53cml0YWJsZSA9IHRydWU7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTsgfSB9IHJldHVybiBmdW5jdGlvbiAoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7IGlmIChwcm90b1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7IGlmIChzdGF0aWNQcm9wcykgZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvciwgc3RhdGljUHJvcHMpOyByZXR1cm4gQ29uc3RydWN0b3I7IH07IH0oKTtcblxudmFyIF9Xcml0ZXJTZXJ2aWNlID0gcmVxdWlyZSgnLi9Xcml0ZXJTZXJ2aWNlJyk7XG5cbnZhciBfV3JpdGVyU2VydmljZTIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF9Xcml0ZXJTZXJ2aWNlKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgZGVmYXVsdDogb2JqIH07IH1cblxuZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3RvcikgeyBpZiAoIShpbnN0YW5jZSBpbnN0YW5jZW9mIENvbnN0cnVjdG9yKSkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpOyB9IH1cblxuLyoqXG4gKiBQcm92aWRlcyBhbiBFeHBvcnRTZXJ2aWNlIHRoYXQgdXNlcyBXcml0ZXJTZXJ2aWNlIHRvIG1lbnRhaW4gYW4gaW4tbWVtb3J5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBDU1YgZmlsZS5cbiAqIFVzZXMgZG93bmxvYWRDU1YgdG8gbWFwIHRoZSBbZGF0YV0gdmlhIHRoZSBXcml0ZXIgdG8gYSBCbG9iIGFuZCBpbml0aWF0ZSBkb3dubG9hZCB3aGljaCB0cmlnZ2VycyB0aGUgZG93bmxvYWQgb2YgdGhlIGFjdHVhbCBmaWxlIGluIHRoZSBicm93c2VyLlxuICogUHJvdmlkZXMgc3RhdGljIG1ldGhvZHMgZm9yIFNpbmdsZXRvbi1saWtlIHVzYWdlLlxuICovXG52YXIgQ1NWRXhwb3J0U2VydmljZSA9IGZ1bmN0aW9uICgpIHtcbiAgLyoqXG4gICAqIERlZmF1bHQgY29uc3RydWN0b3IuIFRha2VzIGFuIG9wdGlvbmFsIG9wdGlvbnMgcGFyYW0uXG4gICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyAtIFByb3ZpZGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAqL1xuICBmdW5jdGlvbiBDU1ZFeHBvcnRTZXJ2aWNlKG9wdGlvbnMpIHtcbiAgICBfY2xhc3NDYWxsQ2hlY2sodGhpcywgQ1NWRXhwb3J0U2VydmljZSk7XG5cbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNob3J0aGFuZCBmb3IgY3JlYXRlQ1NWKCkgd2l0aCBhIHByZS1zZXQgd3JpdGVyVHlwZVxuICAqL1xuXG5cbiAgX2NyZWF0ZUNsYXNzKENTVkV4cG9ydFNlcnZpY2UsIFt7XG4gICAga2V5OiAnY3JlYXRlQ1NWQmxvYicsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGNyZWF0ZUNTVkJsb2IoZGF0YSkge1xuICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlQ1NWKGRhdGEpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAgKiBTaG9ydGhhbmQgZm9yIGNyZWF0ZUNTVigpIHdpdGggYSBwcmUtc2V0IHdyaXRlclR5cGVcbiAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdkYXRhVG9TdHJpbmcnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBkYXRhVG9TdHJpbmcoZGF0YSkge1xuICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlQ1NWKGRhdGEsICdzdHJpbmcnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgQmxvYiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgZGF0YSBhbmQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge0FycmF5fSBkYXRhIC0gQW4gYXJyYXkgb2YgSlNPTiBvYmplY3RzIHRoYXQgd2lsbCBiZSBtYXBwZWQgdG8gdGhlIEJsb2IuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSB3cml0ZXJUeXBlIC0gRU5VTSBmb3IgY2hvb3NpbmcgdGhlIHJldHVybiB0eXBlLiBEZWZhdWx0IHRvICdibG8nXG4gICAgICogQHJldHVybiB7T2JqZWN0fFN0cmluZ30gLSBUaGUgQmxvYiBvYmplY3QgKElzIGFuIGluc3RhbmNlIG9mIEJsb2IsIGJ1dCB0eXBlb2YgT2JqZWN0KSBvciBhIFN0cmluZyB2ZXJzaW9uIG9mIHRoZSBDU1Ygd2l0aCBuZXdsaW5lcy5cbiAgICAgKi9cblxuICB9LCB7XG4gICAga2V5OiAnY3JlYXRlQ1NWJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gY3JlYXRlQ1NWKGRhdGEpIHtcbiAgICAgIHZhciB3cml0ZXJUeXBlID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiAnYmxvYic7XG5cbiAgICAgIHZhciBfcmVmID0gdGhpcy5vcHRpb25zIHx8IHt9LFxuICAgICAgICAgIG9wdGlvbnNDb2x1bW5zID0gX3JlZi5jb2x1bW5zLFxuICAgICAgICAgIG9wdGlvbnNDb250ZW50VHlwZSA9IF9yZWYuY29udGVudFR5cGUsXG4gICAgICAgICAgb3B0aW9uc0RlbGltZXRlciA9IF9yZWYuZGVsaW1ldGVyLFxuICAgICAgICAgIG9wdGlvbnNEZWxpbWl0ZXIgPSBfcmVmLmRlbGltaXRlcixcbiAgICAgICAgICBvcHRpb25zRm9ybWF0dGVycyA9IF9yZWYuZm9ybWF0dGVycyxcbiAgICAgICAgICBvcHRpb25zSGVhZGVycyA9IF9yZWYuaGVhZGVycyxcbiAgICAgICAgICBvcHRpb25zSW5jbHVkZUhlYWRlcnMgPSBfcmVmLmluY2x1ZGVIZWFkZXJzO1xuXG4gICAgICB2YXIgY29udGVudFR5cGUgPSBvcHRpb25zQ29udGVudFR5cGUgfHwgJ3RleHQvY3N2JztcbiAgICAgIHZhciBkZWxpbWl0ZXIgPSBvcHRpb25zRGVsaW1ldGVyIHx8ICcsJztcbiAgICAgIHZhciBmb3JtYXR0ZXJzID0gb3B0aW9uc0Zvcm1hdHRlcnMgfHwge307XG4gICAgICB2YXIgZ2V0Rm9ybWF0ZXIgPSBmdW5jdGlvbiBnZXRGb3JtYXRlcihoZWFkZXIpIHtcbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlcnNbaGVhZGVyXSB8fCBmdW5jdGlvbiAodikge1xuICAgICAgICAgIHJldHVybiB2O1xuICAgICAgICB9O1xuICAgICAgfTtcbiAgICAgIHZhciBoZWFkZXJOYW1lcyA9IG9wdGlvbnNIZWFkZXJzIHx8IHt9O1xuICAgICAgdmFyIGhlYWRlcnMgPSBvcHRpb25zQ29sdW1ucyB8fCBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhkYXRhWzBdKTtcbiAgICAgIHZhciBpbmNsdWRlSGVhZGVycyA9IG9wdGlvbnNJbmNsdWRlSGVhZGVycztcbiAgICAgIHZhciB3cml0ZXIgPSBuZXcgX1dyaXRlclNlcnZpY2UyLmRlZmF1bHQoZGVsaW1pdGVyLCBjb250ZW50VHlwZSk7XG5cbiAgICAgIGlmIChpbmNsdWRlSGVhZGVycyA9PT0gdW5kZWZpbmVkIHx8IGluY2x1ZGVIZWFkZXJzKSB7XG4gICAgICAgIGhlYWRlcnMuZm9yRWFjaChmdW5jdGlvbiAoaGVhZGVyKSB7XG4gICAgICAgICAgcmV0dXJuIHdyaXRlci53cml0ZVZhbHVlKGhlYWRlck5hbWVzW2hlYWRlcl0gfHwgaGVhZGVyKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdyaXRlci53cml0ZUxpbmUoKTtcbiAgICAgIH1cbiAgICAgIGRhdGEuZm9yRWFjaChmdW5jdGlvbiAocm93KSB7XG4gICAgICAgIGhlYWRlcnMuZm9yRWFjaChmdW5jdGlvbiAoaGVhZGVyKSB7XG4gICAgICAgICAgcmV0dXJuIHdyaXRlci53cml0ZVZhbHVlKGdldEZvcm1hdGVyKGhlYWRlcikocm93W2hlYWRlcl0pKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHdyaXRlci53cml0ZUxpbmUoKTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHdyaXRlclR5cGUgPT09ICdzdHJpbmcnID8gd3JpdGVyLnRvU3RyaW5nKCkgOiB3cml0ZXIudG9CbG9iKCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFRyaWdnZXJzIHRoZSBkb3dubG9hZCBvZiB0aGUgZmlsZS5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGJsb2IgLSBUaGUgYmxvYiB0byBiZSBkb3dubG9hZGVkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZW5hbWUgLSBOYW1lIG9mIHRoZSBmaWxlLlxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdkb3dubG9hZCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGRvd25sb2FkKGJsb2IsIGZpbGVuYW1lKSB7XG4gICAgICBpZiAobmF2aWdhdG9yLm1zU2F2ZUJsb2IpIHtcbiAgICAgICAgbmF2aWdhdG9yLm1zU2F2ZUJsb2IoYmxvYiwgZmlsZW5hbWUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB2YXIgbGluayA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ0EnKTtcbiAgICAgIHZhciB1cmwgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpO1xuICAgICAgbGluay5ocmVmID0gdXJsO1xuICAgICAgbGluay5kb3dubG9hZCA9IGZpbGVuYW1lO1xuICAgICAgbGluay5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChsaW5rKTtcbiAgICAgIGxpbmsuY2xpY2soKTtcbiAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQobGluayk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHBhc3NlcyB0aGUgYmxvYiBhbmQgZmlsZW5hbWUgcGFyYW1zIHRvIHRoZSBkb3dubG9hZCgpIG1ldGhvZC4gSW4gY2FzZSBvZiBlcnJvciwgY2FsbHMgdGhlIG9uRXJyb3IgY2FsbGJhY2sgKGlmIHByb3ZpZGVkKSBhbmQgcHJpbnRzIGEgZXJyb3IgbWVzYWdlIGlmIGRldk1vZGUgaXMgZW5hYmxlZCB2aWEgb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0gIHtBcnJheX0gZGF0YSAtIEFuIGFycmF5IG9mIG9iamVjdHMgdG8gbWFwIGFuZCBzdG9yZS5cbiAgICAgKi9cblxuICB9LCB7XG4gICAga2V5OiAnZG93bmxvYWRDU1YnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBkb3dubG9hZENTVihkYXRhKSB7XG4gICAgICB0cnkge1xuICAgICAgICB2YXIgYmxvYiA9IHRoaXMuY3JlYXRlQ1NWKGRhdGEsICdibG9iJyk7XG4gICAgICAgIHZhciBmaWxlbmFtZSA9IHRoaXMub3B0aW9ucy5maWxlbmFtZSB8fCAnZXhwb3J0LScgKyAobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwIHwgMCkgKyAnLmNzdic7XG4gICAgICAgIHRoaXMuZG93bmxvYWQoYmxvYiwgZmlsZW5hbWUpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZGV2TW9kZSkge1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGRvd25sb2FkaW5nIENTVi4gU2VuZCB0aGlzIGxvZyB0byB0aGUgZGV2ZWxvcGVyczogXFxuJywgZXJyKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLm9uRXJyb3IpIHtcbiAgICAgICAgICB0aGlzLm9wdGlvbnMub25FcnJvcihlcnIpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAndG9TdHJpbmcnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiB0b1N0cmluZyhkYXRhKSB7XG4gICAgICB2YXIgd3JpdGVyID0gbmV3IF9Xcml0ZXJTZXJ2aWNlMi5kZWZhdWx0KGRlbGltaXRlciwgY29udGVudFR5cGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3J0aGFuZCBmb3IgY29uc3RydWN0b3IuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zXG4gICAgICogQHJldHVybiB7T2JqZWN0fSAtIEFuIGluc3RhbmNlIG9mIENTVkV4cG9ydFNlcnZpY2VcbiAgICAgKi9cblxuICB9XSwgW3tcbiAgICBrZXk6ICdjcmVhdGUnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBjcmVhdGUob3B0aW9ucykge1xuICAgICAgcmV0dXJuIG5ldyBDU1ZFeHBvcnRTZXJ2aWNlKG9wdGlvbnMpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTaG9ydGhhbmQgZm9yIGluaXRpYWxpemF0aW9uIGFuZCBkb3dubG9hZCgpIGNhbGwuXG4gICAgICogQHBhcmFtICB7QXJyYXl9IGRhdGEgLSBBbiBhcnJheSBvZiBvYmplY3RzIHRvIG1hcCBhbmQgc3RvcmUuXG4gICAgICogQHJldHVybiB7dW5kZWZpbmVkfVxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdkb3dubG9hZCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIGRvd25sb2FkKGRhdGEpIHtcbiAgICAgIHZhciBvcHRpb25zID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiB7fTtcblxuICAgICAgcmV0dXJuIG5ldyBDU1ZFeHBvcnRTZXJ2aWNlKG9wdGlvbnMpLmRvd25sb2FkQ1NWKGRhdGEpO1xuICAgIH1cbiAgfV0pO1xuXG4gIHJldHVybiBDU1ZFeHBvcnRTZXJ2aWNlO1xufSgpO1xuXG5leHBvcnRzLmRlZmF1bHQgPSBDU1ZFeHBvcnRTZXJ2aWNlOyJdfQ==
let CSVExportService = require('json2csvexporter').default;
const exporter = CSVExportService.create();
function download(htmlTable) {
exporter.downloadCSV(tableToJson(htmlTable));
}
// Credits: http://johndyer.name/html-table-to-json/
function tableToJson(table) {
let data = []; // first row needs to be headers
var headers = [];
for (var i=0; i<table.rows[0].cells.length; i++) {
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi,'');
}
// go through cells
for (var i=1; i<table.rows.length; i++) {
var tableRow = table.rows[i]; var rowData = {};
for (var j=0; j<tableRow.cells.length; j++) {
rowData[ headers[j] ] = tableRow.cells[j].innerHTML;
}
data.push(rowData);
}
return data;
}
const table = document.querySelector('#data-table');
const button = document.querySelector('#dl-btn');
button.addEventListener('click', () => download(document.querySelector('#data-table')));
;}, 0)
{
"name": "json2csvexporter-demo",
"version": "1.0.0",
"dependencies": {
"json2csvexporter": "0.2.4"
}
}
<!-- contents of this file will be placed inside the <body> -->
<table id="data-table" class="table">
<tr>
<th>Make</th>
<th>Model</th>
<th>Year</th>
</tr>
<tr>
<td>Toyota</td>
<td>Corolla</td>
<td>2014</td>
</tr>
<tr>
<td>Ford</td>
<td>Mustang</td>
<td>1970</td>
</tr>
<tr>
<td>Honda</td>
<td>Civic</td>
<td>2007</td>
</tr>
</table>
<button type="button" class="btn btn-default" id='dl-btn'>Download CSV</button>
<!-- contents of this file will be placed inside the <head> -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment