tabulator-tables
Version:
Interactive table generation JavaScript library
900 lines (714 loc) • 20.2 kB
JavaScript
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/* Tabulator v4.3.0 (c) Oliver Folkerd */
var Download = function Download(table) {
this.table = table; //hold Tabulator object
this.fields = {}; //hold filed multi dimension arrays
this.columnsByIndex = []; //hold columns in their order in the table
this.columnsByField = {}; //hold columns with lookup by field name
this.config = {};
};
//trigger file download
Download.prototype.download = function (type, filename, options, interceptCallback) {
var self = this,
downloadFunc = false;
this.processConfig();
function buildLink(data, mime) {
if (interceptCallback) {
if (interceptCallback === true) {
self.triggerDownload(data, mime, type, filename, true);
} else {
interceptCallback(data);
}
} else {
self.triggerDownload(data, mime, type, filename);
}
}
if (typeof type == "function") {
downloadFunc = type;
} else {
if (self.downloaders[type]) {
downloadFunc = self.downloaders[type];
} else {
console.warn("Download Error - No such download type found: ", type);
}
}
this.processColumns();
if (downloadFunc) {
downloadFunc.call(this, self.processDefinitions(), self.processData(), options || {}, buildLink, this.config);
}
};
Download.prototype.processConfig = function () {
var config = { //download config
columnGroups: true,
rowGroups: true,
columnCalcs: true
};
if (this.table.options.downloadConfig) {
for (var key in this.table.options.downloadConfig) {
config[key] = this.table.options.downloadConfig[key];
}
}
if (config.rowGroups && this.table.options.groupBy && this.table.modExists("groupRows")) {
this.config.rowGroups = true;
}
if (config.columnGroups && this.table.columnManager.columns.length != this.table.columnManager.columnsByIndex.length) {
this.config.columnGroups = true;
}
if (config.columnCalcs && this.table.modExists("columnCalcs")) {
this.config.columnCalcs = true;
}
};
Download.prototype.processColumns = function () {
var self = this;
self.columnsByIndex = [];
self.columnsByField = {};
self.table.columnManager.columnsByIndex.forEach(function (column) {
if (column.field && column.definition.download !== false && (column.visible || !column.visible && column.definition.download)) {
self.columnsByIndex.push(column);
self.columnsByField[column.field] = column;
}
});
};
Download.prototype.processDefinitions = function () {
var self = this,
processedDefinitions = [];
if (this.config.columnGroups) {
self.table.columnManager.columns.forEach(function (column) {
var colData = self.processColumnGroup(column);
if (colData) {
processedDefinitions.push(colData);
}
});
} else {
self.columnsByIndex.forEach(function (column) {
if (column.download !== false) {
//isolate definiton from defintion object
processedDefinitions.push(self.processDefinition(column));
}
});
}
return processedDefinitions;
};
Download.prototype.processColumnGroup = function (column) {
var _this = this;
var subGroups = column.columns,
maxDepth = 0;
var processedColumn = this.processDefinition(column);
var groupData = {
type: "group",
title: processedColumn.title,
depth: 1
};
if (subGroups.length) {
groupData.subGroups = [];
groupData.width = 0;
subGroups.forEach(function (subGroup) {
var subGroupData = _this.processColumnGroup(subGroup);
if (subGroupData.depth > maxDepth) {
maxDepth = subGroupData.depth;
}
if (subGroupData) {
groupData.width += subGroupData.width;
groupData.subGroups.push(subGroupData);
}
});
groupData.depth += maxDepth;
if (!groupData.width) {
return false;
}
} else {
if (column.field && column.definition.download !== false && (column.visible || !column.visible && column.definition.download)) {
groupData.width = 1;
groupData.definition = processedColumn;
} else {
return false;
}
}
return groupData;
};
Download.prototype.processDefinition = function (column) {
var def = {};
for (var key in column.definition) {
def[key] = column.definition[key];
}
if (typeof column.definition.downloadTitle != "undefined") {
def.title = column.definition.downloadTitle;
}
return def;
};
Download.prototype.processData = function () {
var _this2 = this;
var self = this,
data = [],
groups = [],
calcs = {};
if (this.config.rowGroups) {
groups = this.table.modules.groupRows.getGroups();
groups.forEach(function (group) {
data.push(_this2.processGroupData(group));
});
} else {
data = self.table.rowManager.getData(true, "download");
}
if (this.config.columnCalcs) {
calcs = this.table.getCalcResults();
data = {
calcs: calcs,
data: data
};
}
//bulk data processing
if (typeof self.table.options.downloadDataFormatter == "function") {
data = self.table.options.downloadDataFormatter(data);
}
return data;
};
Download.prototype.processGroupData = function (group) {
var _this3 = this;
var subGroups = group.getSubGroups();
var groupData = {
type: "group",
key: group.key
};
if (subGroups.length) {
groupData.subGroups = [];
subGroups.forEach(function (subGroup) {
groupData.subGroups.push(_this3.processGroupData(subGroup));
});
} else {
groupData.rows = group.getData(true, "download");
}
return groupData;
};
Download.prototype.triggerDownload = function (data, mime, type, filename, newTab) {
var element = document.createElement('a'),
blob = new Blob([data], { type: mime }),
filename = filename || "Tabulator." + (typeof type === "function" ? "txt" : type);
blob = this.table.options.downloadReady.call(this.table, data, blob);
if (blob) {
if (newTab) {
window.open(window.URL.createObjectURL(blob));
} else {
if (navigator.msSaveOrOpenBlob) {
navigator.msSaveOrOpenBlob(blob, filename);
} else {
element.setAttribute('href', window.URL.createObjectURL(blob));
//set file title
element.setAttribute('download', filename);
//trigger download
element.style.display = 'none';
document.body.appendChild(element);
element.click();
//remove temporary link element
document.body.removeChild(element);
}
}
if (this.table.options.downloadComplete) {
this.table.options.downloadComplete();
}
}
};
//nested field lookup
Download.prototype.getFieldValue = function (field, data) {
var column = this.columnsByField[field];
if (column) {
return column.getFieldValue(data);
}
return false;
};
Download.prototype.commsReceived = function (table, action, data) {
switch (action) {
case "intercept":
this.download(data.type, "", data.options, data.intercept);
break;
}
};
//downloaders
Download.prototype.downloaders = {
csv: function csv(columns, data, options, setFileContents, config) {
var self = this,
titles = [],
fields = [],
delimiter = options && options.delimiter ? options.delimiter : ",",
fileContents,
output;
//build column headers
function parseSimpleTitles() {
columns.forEach(function (column) {
titles.push('"' + String(column.title).split('"').join('""') + '"');
fields.push(column.field);
});
}
function parseColumnGroup(column, level) {
if (column.subGroups) {
column.subGroups.forEach(function (subGroup) {
parseColumnGroup(subGroup, level + 1);
});
} else {
titles.push('"' + String(column.title).split('"').join('""') + '"');
fields.push(column.definition.field);
}
}
if (config.columnGroups) {
console.warn("Download Warning - CSV downloader cannot process column groups");
columns.forEach(function (column) {
parseColumnGroup(column, 0);
});
} else {
parseSimpleTitles();
}
//generate header row
fileContents = [titles.join(delimiter)];
function parseRows(data) {
//generate each row of the table
data.forEach(function (row) {
var rowData = [];
fields.forEach(function (field) {
var value = self.getFieldValue(field, row);
switch (typeof value === "undefined" ? "undefined" : _typeof(value)) {
case "object":
value = JSON.stringify(value);
break;
case "undefined":
case "null":
value = "";
break;
default:
value = value;
}
//escape quotation marks
rowData.push('"' + String(value).split('"').join('""') + '"');
});
fileContents.push(rowData.join(delimiter));
});
}
function parseGroup(group) {
if (group.subGroups) {
group.subGroups.forEach(function (subGroup) {
parseGroup(subGroup);
});
} else {
parseRows(group.rows);
}
}
if (config.columnCalcs) {
console.warn("Download Warning - CSV downloader cannot process column calculations");
data = data.data;
}
if (config.rowGroups) {
console.warn("Download Warning - CSV downloader cannot process row groups");
data.forEach(function (group) {
parseGroup(group);
});
} else {
parseRows(data);
}
output = fileContents.join("\n");
if (options.bom) {
output = "\uFEFF" + output;
}
setFileContents(output, "text/csv");
},
json: function json(columns, data, options, setFileContents, config) {
var fileContents;
if (config.columnCalcs) {
console.warn("Download Warning - CSV downloader cannot process column calculations");
data = data.data;
}
fileContents = JSON.stringify(data, null, '\t');
setFileContents(fileContents, "application/json");
},
pdf: function pdf(columns, data, options, setFileContents, config) {
var self = this,
fields = [],
header = [],
body = [],
calcs = {},
headerDepth = 1,
table = "",
autoTableParams = {},
rowGroupStyles = options.rowGroupStyles || {
fontStyle: "bold",
fontSize: 12,
cellPadding: 6,
fillColor: 220
},
rowCalcStyles = options.rowCalcStyles || {
fontStyle: "bold",
fontSize: 10,
cellPadding: 4,
fillColor: 232
},
jsPDFParams = options.jsPDF || {},
title = options && options.title ? options.title : "";
if (config.columnCalcs) {
calcs = data.calcs;
data = data.data;
}
if (!jsPDFParams.orientation) {
jsPDFParams.orientation = options.orientation || "landscape";
}
if (!jsPDFParams.unit) {
jsPDFParams.unit = "pt";
}
//build column headers
function parseSimpleTitles() {
columns.forEach(function (column) {
if (column.field) {
header.push(column.title || "");
fields.push(column.field);
}
});
header = [header];
}
function parseColumnGroup(column, level) {
var colSpan = column.width,
rowSpan = 1,
col = {
content: column.title || ""
};
if (column.subGroups) {
column.subGroups.forEach(function (subGroup) {
parseColumnGroup(subGroup, level + 1);
});
rowSpan = 1;
} else {
fields.push(column.definition.field);
rowSpan = headerDepth - level;
}
col.rowSpan = rowSpan;
// col.colSpan = colSpan;
header[level].push(col);
colSpan--;
if (rowSpan > 1) {
for (var i = level + 1; i < headerDepth; i++) {
header[i].push("");
}
}
for (var i = 0; i < colSpan; i++) {
header[level].push("");
}
}
if (config.columnGroups) {
columns.forEach(function (column) {
if (column.depth > headerDepth) {
headerDepth = column.depth;
}
});
for (var i = 0; i < headerDepth; i++) {
header.push([]);
}
columns.forEach(function (column) {
parseColumnGroup(column, 0);
});
} else {
parseSimpleTitles();
}
function parseValue(value) {
switch (typeof value === "undefined" ? "undefined" : _typeof(value)) {
case "object":
value = JSON.stringify(value);
break;
case "undefined":
case "null":
value = "";
break;
default:
value = value;
}
return value;
}
function parseRows(data) {
//build table rows
data.forEach(function (row) {
body.push(parseRow(row));
});
}
function parseRow(row, styles) {
var rowData = [];
fields.forEach(function (field) {
var value = self.getFieldValue(field, row);
value = parseValue(value);
if (styles) {
rowData.push({
content: value,
styles: styles
});
} else {
rowData.push(value);
}
});
return rowData;
}
function parseGroup(group, calcObj) {
var groupData = [];
groupData.push({ content: parseValue(group.key), colSpan: fields.length, styles: rowGroupStyles });
body.push(groupData);
if (group.subGroups) {
group.subGroups.forEach(function (subGroup) {
parseGroup(subGroup, calcObj[group.key] ? calcObj[group.key].groups || {} : {});
});
} else {
if (config.columnCalcs) {
addCalcRow(calcObj, group.key, "top");
}
parseRows(group.rows);
if (config.columnCalcs) {
addCalcRow(calcObj, group.key, "bottom");
}
}
}
function addCalcRow(calcs, selector, pos) {
var calcData = calcs[selector];
if (calcData) {
if (pos) {
calcData = calcData[pos];
}
if (Object.keys(calcData).length) {
body.push(parseRow(calcData, rowCalcStyles));
}
}
}
if (config.rowGroups) {
data.forEach(function (group) {
parseGroup(group, calcs);
});
} else {
if (config.columnCalcs) {
addCalcRow(calcs, "top");
}
parseRows(data);
if (config.columnCalcs) {
addCalcRow(calcs, "bottom");
}
}
var doc = new jsPDF(jsPDFParams); //set document to landscape, better for most tables
if (options && options.autoTable) {
if (typeof options.autoTable === "function") {
autoTableParams = options.autoTable(doc) || {};
} else {
autoTableParams = options.autoTable;
}
}
if (title) {
autoTableParams.addPageContent = function (data) {
doc.text(title, 40, 30);
};
}
autoTableParams.head = header;
autoTableParams.body = body;
doc.autoTable(autoTableParams);
if (options && options.documentProcessing) {
options.documentProcessing(doc);
}
setFileContents(doc.output("arraybuffer"), "application/pdf");
},
xlsx: function xlsx(columns, data, options, setFileContents, config) {
var self = this,
sheetName = options.sheetName || "Sheet1",
workbook = { SheetNames: [], Sheets: {} },
calcs = {},
groupRowIndexs = [],
groupColumnIndexs = [],
calcRowIndexs = [],
output;
if (config.columnCalcs) {
calcs = data.calcs;
data = data.data;
}
function generateSheet() {
var titles = [],
fields = [],
rows = [],
worksheet;
//convert rows to worksheet
function rowsToSheet() {
var sheet = {};
var range = { s: { c: 0, r: 0 }, e: { c: fields.length, r: rows.length } };
XLSX.utils.sheet_add_aoa(sheet, rows);
sheet['!ref'] = XLSX.utils.encode_range(range);
var merges = generateMerges();
if (merges.length) {
sheet["!merges"] = merges;
}
return sheet;
}
function parseSimpleTitles() {
//get field lists
columns.forEach(function (column) {
titles.push(column.title);
fields.push(column.field);
});
rows.push(titles);
}
function parseColumnGroup(column, level) {
if (typeof titles[level] === "undefined") {
titles[level] = [];
}
if (typeof groupColumnIndexs[level] === "undefined") {
groupColumnIndexs[level] = [];
}
if (column.width > 1) {
groupColumnIndexs[level].push({
type: "hoz",
start: titles[level].length,
end: titles[level].length + column.width - 1
});
}
titles[level].push(column.title);
if (column.subGroups) {
column.subGroups.forEach(function (subGroup) {
parseColumnGroup(subGroup, level + 1);
});
} else {
fields.push(column.definition.field);
padColumnTitles(fields.length - 1, level);
groupColumnIndexs[level].push({
type: "vert",
start: fields.length - 1
});
}
}
function padColumnTitles() {
var max = 0;
titles.forEach(function (title) {
var len = title.length;
if (len > max) {
max = len;
}
});
titles.forEach(function (title) {
var len = title.length;
if (len < max) {
for (var i = len; i < max; i++) {
title.push("");
}
}
});
}
if (config.columnGroups) {
columns.forEach(function (column) {
parseColumnGroup(column, 0);
});
titles.forEach(function (title) {
rows.push(title);
});
} else {
parseSimpleTitles();
}
function generateMerges() {
var output = [];
groupRowIndexs.forEach(function (index) {
output.push({ s: { r: index, c: 0 }, e: { r: index, c: fields.length - 1 } });
});
groupColumnIndexs.forEach(function (merges, level) {
merges.forEach(function (merge) {
if (merge.type === "hoz") {
output.push({ s: { r: level, c: merge.start }, e: { r: level, c: merge.end } });
} else {
if (level != titles.length - 1) {
output.push({ s: { r: level, c: merge.start }, e: { r: titles.length - 1, c: merge.start } });
}
}
});
});
return output;
}
//generate each row of the table
function parseRows(data) {
data.forEach(function (row) {
rows.push(parseRow(row));
});
}
function parseRow(row) {
var rowData = [];
fields.forEach(function (field) {
var value = self.getFieldValue(field, row);
rowData.push(!(value instanceof Date) && (typeof value === "undefined" ? "undefined" : _typeof(value)) === "object" ? JSON.stringify(value) : value);
});
return rowData;
}
function addCalcRow(calcs, selector, pos) {
var calcData = calcs[selector];
if (calcData) {
if (pos) {
calcData = calcData[pos];
}
if (Object.keys(calcData).length) {
calcRowIndexs.push(rows.length);
rows.push(parseRow(calcData));
}
}
}
function parseGroup(group, calcObj) {
var groupData = [];
groupData.push(group.key);
groupRowIndexs.push(rows.length);
rows.push(groupData);
if (group.subGroups) {
group.subGroups.forEach(function (subGroup) {
parseGroup(subGroup, calcObj[group.key] ? calcObj[group.key].groups || {} : {});
});
} else {
if (config.columnCalcs) {
addCalcRow(calcObj, group.key, "top");
}
parseRows(group.rows);
if (config.columnCalcs) {
addCalcRow(calcObj, group.key, "bottom");
}
}
}
if (config.rowGroups) {
data.forEach(function (group) {
parseGroup(group, calcs);
});
} else {
if (config.columnCalcs) {
addCalcRow(calcs, "top");
}
parseRows(data);
if (config.columnCalcs) {
addCalcRow(calcs, "bottom");
}
}
worksheet = rowsToSheet();
return worksheet;
}
if (options.sheetOnly) {
setFileContents(generateSheet());
return;
}
if (options.sheets) {
for (var sheet in options.sheets) {
if (options.sheets[sheet] === true) {
workbook.SheetNames.push(sheet);
workbook.Sheets[sheet] = generateSheet();
} else {
workbook.SheetNames.push(sheet);
this.table.modules.comms.send(options.sheets[sheet], "download", "intercept", {
type: "xlsx",
options: { sheetOnly: true },
intercept: function intercept(data) {
workbook.Sheets[sheet] = data;
}
});
}
}
} else {
workbook.SheetNames.push(sheetName);
workbook.Sheets[sheetName] = generateSheet();
}
//convert workbook to binary array
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) {
view[i] = s.charCodeAt(i) & 0xFF;
}return buf;
}
output = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'binary' });
setFileContents(s2ab(output), "application/octet-stream");
}
};
Tabulator.prototype.registerModule("download", Download);