JSReports/Public/ecma/JSReports.ecma.js

909 lines
37 KiB
JavaScript
Executable File

JSReports = function(input){
// Require html2canvas.min.js, purify.min.js & jspdf.umd.min.js for PDF files.
const self = this,
default_settings = {
nulls : false,
default_value : null,
timeout : 2000,
cache_box : "body",
preload_show_exception : true,
preload_timeout : 2000,
frames_per_second : 24,
default_cache_box : "body",
width : 17,
margin_top : 20,
margin_left : 20,
margin_right : 20,
margin_bottom : 20,
// margin : [50, 50, 50, 40], // [top, right, bottom, left]
proxy : null,
autostart : true,
hash_alphabet : "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
hash_length : 13,
default_list_mode : "ul",
dpi : 96,
page_format : "a4",
margin_footer : 5,
margin_header : 5,
header_height : 30,
footer_height : 10,
date_format : "{dd}/{mm}/{yyyy} {hh}:{ii}:{ss}",
months : [
"January", "Febrary", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"
],
week_days : [
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
],
// pdf.addFont("/data/OpenSans-Regular.ttf", "Open Sans", "normal");
default_fonts : [
["FA5FB", "https://cdn.k3y.pw/fonts/FontAwesome/5.15/fa-brands-400.ttf", "normal"],
["FA5FR", "https://cdn.k3y.pw/fonts/FontAwesome/5.15/fa-regular-400.ttf", "normal"],
["FA5FS", "https://cdn.k3y.pw/fonts/FontAwesome/5.15/fa-solid-900.ttf", "normal"],
// ["Open Sans Condensed", "https://cdn.k3y.pw/fonts/Open_Sans/static/OpenSans_Condensed/OpenSans_Condensed-Bold.ttf", "bold"],
// ["Open Sans Condensed", "https://cdn.k3y.pw/fonts/Open_Sans/static/OpenSans_Condensed/OpenSans_Condensed-Medium.ttf", "normal"],
// ["Open Sans Condensed", "https://cdn.k3y.pw/fonts/Open_Sans/static/OpenSans_Condensed/OpenSans_Condensed-Italic.ttf", "italic"],
// ["Open Sans", "https://cdn.k3y.pw/fonts/Open_Sans/static/OpenSans/OpenSans-Bold.ttf", "bold"],
// ["Open Sans", "https://cdn.k3y.pw/fonts/Open_Sans/static/OpenSans/OpenSans-Medium.ttf", "normal"],
// ["Open Sans", "https://cdn.k3y.pw/fonts/Open_Sans/static/OpenSans/OpenSans-Italic.ttf", "italic"]
["Open Sans", "https://cdn.k3y.pw/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf", "normal"],
["Oxygen", "https://cdn.k3y.pw/fonts/Oxygen/Oxygen-Regular.ttf", "normal"],
["Roboto", "https://cdn.k3y.pw/fonts/Roboto/Roboto-Medium.ttf", "normal"],
["Roboto Mono", "https://cdn.k3y.pw/fonts/Roboto_Mono/RobotoMono-VariableFont_wght.ttf", "normal"],
["Source Code Pro", "https://cdn.k3y.pw/fonts/Source_Code_Pro/SourceCodePro-VariableFont_wght.ttf", "normal"],
["Ubuntu", "https://cdn.k3y.pw/fonts/Ubuntu/Ubuntu-Medium.ttf", "normal"],
["Ubuntu Mono", "https://cdn.k3y.pw/fonts/Ubuntu_Mono/UbuntuMono-Regular.ttf", "normal"]
]
},
events = {},
hashes = [],
fonts = {};
let started = false,
cache_box = document,
proxy = null,
thread = null,
is_ready = false,
months = [],
week_days = [];
const event_execute = this.event_execute = key => events[key] && events[key].forEach(event => event && event());
const event_add = this.event_add = (key, method) => {
if(!key || typeof method != "function")
return null;
let i = 0;
const l = (events[key] || (events[key] = [])).length;
for(; i < l; i ++)
if(!events[key][i])
break;
events[key][i] = method;
return i;
};
const event_remove = this.event_remove = (key, i) => key && !isNaN(i) && events[key] && events[key][i] && (events[key][i] = null);
const is_html_item = this.is_html_item = item => item && (item.tagName || item.nodeName);
const default_value = this.default_value = (_default, nulls) => _default !== undefined && (_default !== null || (typeof nulls == "boolean" ? nulls : settings("nulls", null, false, false))) ? _default : settings(["default_value", "default"], null, null, true);
const settings = this.settings = (names, inputs, _default, nulls) => {
if(!names)
return default_value(_default, nulls);
const l = (names instanceof Array ? names : names = [names]).length,
m = (inputs = (typeof inputs == "object" ? inputs instanceof Array ? inputs : [inputs] : []).concat([input, default_settings])).length;
typeof nulls != "boolean" && (nulls = settings("nulls", null, false, false));
for(let j = 0; j < m; j ++)
if(inputs[j] && typeof inputs[j] == "object")
for(let i = 0; i < l; i ++)
if(names[i] && inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null))
return inputs[j][names[i]];
return default_value(_default, nulls);
};
const threads_method = () => event_execute("threads");
const threads_start = this.threads_start = frames_per_second => thread === null && (thread = setInterval(threads_method, 1000 / (isNaN(frames_per_second) ? settings(["frames_per_second", "fps"]) : frames_per_second)));
this.threads_stop = () => {
if(thread === null)
return;
clearInterval(thread);
thread = null;
};
const threads_add = this.threads_add = method => event_add("threads", method);
const threads_remove = this.threads_remove = i => event_remove("threads", i);
const preload = this.preload = (selector, callback) => {
if(typeof callback != "function")
return;
if(!selector){
callback(null, false, "NO_CALLBACK");
return;
};
if(is_html_item(selector)){
callback(selector, false, "OK");
return;
};
if(typeof selector != "string"){
callback(null, false, "NOT_SELECTOR");
return;
};
let item;
try{
if(item = document.querySelector(selector)){
callback(item, false, "OK");
return;
};
}catch(exception){
settings(["preload_show_exception", "show_exception"]) && console.error(excetpion);
callback(null, false, "BAD_SELECTOR");
return;
};
const date = Date.now(),
timeout = settings(["preload_timeout", "timeout"]),
thread = threads_add(() => {
if(item = document.querySelector(selector)){
callback(item, true, "OK");
threads_remove(thread);
}else if(Date.now() - date > timeout){
callback(null, true, "TIMEOUT");
threads_remove(thread);
};
});
};
const ready = position => {
is_ready = true;
cache_box = position;
event_execute("on_ready");
};
this.start = () => {
if(started)
return;
started = true;
threads_start();
proxy = settings("proxy");
preload(settings("cache_box"), position => position ? ready(position) : preload(settings("default_cache_box"), ready));
};
this.on_ready = method => is_ready ? method() : event_add("on_ready", method);
const string_variables = this.string_variables = (string, variables, _default) => {
const l = (variables = variables ? variables instanceof Array ? variables : typeof variables == "object" ? [variables] : [] : []).length;
return string.replace(/\{([^\{\}]+)\}/g, (...arguments) => {
for(let i = 0; i < l; i ++)
if(variables[i][arguments[1]] !== undefined)
return variables[i][arguments[1]];
return _default !== undefined ? _default : arguments[0];
});
};
const base64_to_blob = this.base64_to_blob = (uri, type) => {
const array = atob(uri.split(",")[1]),
l = array.length,
buffer = new ArrayBuffer(l),
integers = new Uint8Array(buffer);
for(let i = 0; i < l; i ++)
buffer[i] = array.charCodeAt(i);
return new Blob([buffer], {type : type});
};
const hash = this.hash = () => {
const alphabet = settings(["hash_alphabet", "alphabet"]),
l = alphabet.length,
length = settings(["hash_length", "length"]);
let hash;
do{
hash = "";
while((hash += alphabet[Math.random() * l >> 0]).length < length);
}while(
hashes.includes(hash) ||
/^[0-9]/.test(hash) ||
document.querySelector("." + hash + ",#" + hash + ",[name=" + hash + "]")
);
hashes.push(hash);
return hash;
};
const grid_to_html = this.grid_to_html = (grid, name) => {
let html = (`
<table class="grid` + (name ? " " + name : "") + `">
<thead>
<tr>
`);
grid.header.forEach((header, j) => html += `<th data-j="` + j + `">` + header + `</th>`);
html += (`
</th>
</thead>
<tbody>
`);
grid.body.forEach((row, i) => {
html += `<tr data-i="` + i + `">`;
row.forEach((value, j) => html += `<td data-j="` + j + `">` + value + `</td>`);
html += `</tr>`;
});
html += (`
</tbody>
</table>
`);
return html;
};
const list_to_html = this.list_to_html = (list, name) => {
const mode = {
ordered : "ol",
unordered : "ul"
}[list.mode] || list.mode || settings(["default_list_mode", "list_mode"]);
let html = `<` + mode + ` class="list` + (name ? " " + name : "") + `"` + (isNaN(list.start) ? `` : ` start="` + list.start + `"`) + `>`;
list.items.forEach((item, i) => html += `<li data-i="` + i + `">` + (typeof item == "object" ? item[0] + list_to_html(item[1]) : item) + `</li>`);
html += `</` + mode + `>`;
return html;
};
const css_to_html = this.css_to_html = (html, css, type, body_size, dpi, callback) => {
const html_item = cache_box.appendChild(document.createElement("div")),
cache = cache_box.appendChild(document.createElement("div")),
images_items = {},
images_data = {},
preload_hash = hash(),
is_doc = type == "doc";
preload("[data-preload=" + preload_hash + "]", preloader => {
preloader.remove();
let loaded = 0;
const images = html_item.querySelectorAll("img"),
l = images.length,
end = (url, image) => {
if(image){
const canvas = cache.appendChild(document.createElement("canvas")),
context = canvas.getContext("2d");
let unit;
canvas.setAttribute("width", image.width);
canvas.setAttribute("height", image.height);
context.drawImage(image, 0, 0, image.width, image.height);
images_data[url] = canvas.toDataURL("image/png", 0.9);
images_items[url].forEach(item => {
item.setAttribute("src", images_data[url]);
if(!is_doc)
return;
if(item.style.width == "auto" && item.style.height && item.style.height != "auto"){
unit = item.style.height.match(/[^0-9\.]+$/)[0];
item.style.width = unit == "%" ? (body_size.height * parseInt(item.style.height) / 1000) + "cm" : (parseInt(item.style.height) * image.width / image.height) + unit;
}else if(item.style.height == "auto" && item.style.width && item.style.width != "auto"){
unit = item.style.width.match(/[^0-9\.]+$/)[0];
item.style.height = unit == "%" ? (body_size.width * parseInt(item.style.width) / 1000) + "cm" : (parseInt(item.style.width) * image.height / image.width) + unit;
};
});
canvas.remove();
};
if(++ loaded < l)
return;
cache.remove();
html = html_item.innerHTML;
html_item.remove();
callback(html);
};
(css ? css instanceof Array ? css : [css] : []).forEach(sheet => sheet && sheet.replace(/\/\*(([^\*]+|[\r\n]+|\*[^\/])*)(\*\/)?|(([^\{]+|[\r\n]+)*)\{(([^\}]+|[\r\n]+)*)\}/g, (...arguments) => {
if(arguments[1])
return;
html_item.querySelectorAll(arguments[5].trim()).forEach(item => {
arguments[6].replace(/([^\s\:]+)\s*\:([^;\}]+)/g, (...subarguments) => item.style[subarguments[1].trim().replace(/\-(.)/g, (all, capital) => capital.toUpperCase())] = subarguments[2]);
item.tagName && item.tagName.toLowerCase() == "table" && item.style.width && !item.hasAttribute("width") && (item.setAttribute("width", item.style.width));
});
}));
is_doc && html_item.querySelectorAll("table").forEach(table => {
if(table.querySelector("colgroup"))
return;
const group = table.insertBefore(document.createElement("colgroup"), table.querySelector("tbody,thead,tfoot")),
sizes = [];
let total = 0,
unsized = 0,
medium = 0;
table.querySelector("tr").childNodes.forEach(column => {
if(!column || column.substr || !column.tagName || !["th", "td"].includes(column.tagName.toLowerCase()))
return;
const matches = column.style.width ? column.style.width.match(/^([0-9\.]+)([^0-9\.]+)$/) : null,
l = column.hasAttribute("colspan") ? Number(column.getAttribute("colspan")) || 1 : 1;
if(!matches){
unsized += l;
sizes.push(null);
return;
};
let size = parseInt(matches[1]);
switch(matches[2].toLowerCase()){
case "px":
size *= dpi / 25.4;
break;
case "mm":
size *= 100 / body_size.width;
break;
case "cm":
size *= 10 / body_size.width;
break;
case "em":
case "ex":
case "in":
size *= 2540 / body_size.width;
break;
case "%":
break;
};
total += size;
size /= l;
for(let i = 0; i < l; i ++)
sizes[sizes.length] = size;
});
medium = total < 100 ? (100 - total) / unsized : 0;
total < 100 && (total = 100);
sizes.forEach(size => group.appendChild(document.createElement("col")).setAttribute("width", 500 * (size === null ? medium : size) / total));
});
if(!images.length){
end();
return;
};
images.forEach(item => {
const url = string_variables(proxy || "{url}", {url : item.getAttribute("src")});
if(images_data[url]){
++ loaded;
item.setAttribute("src", images_data[url]);
return;
};
if(images_items[url]){
++ loaded;
images_items[url].push(item);
return;
};
let image = new Image();
images_items[url] = [item];
image.src = url;
image.crossOrigin = "anonymous";
image.onload = () => end(url, image);
image.onerror = () => end(url, null);
});
});
cache.style.position = html_item.style.position = "absolute";
cache.style.left = html_item.style.left = "100%";
html_item.innerHTML = html + `<div data-preload="` + preload_hash + `"></div>`;
};
const get_page_size = this.get_page_size = format => {
switch(format = format.toLowerCase()){
case "dl":
return [99, 210];
case "letter":
return [216, 279];
case "legal":
return [216, 356];
};
const matches = format.match(/^([abc])(10|[0-9])$/);
if(!matches)
return null;
const [_, type, size] = matches,
results = {
a : [26.3, 37.16],
b : [31.25, 44.2],
c : [28.66, 40.535]
}[type];
for(let i = 9, temporary; i >= size; i --){
temporary = results[0];
results[0] = results[1];
results[1] = 2 * temporary;
};
return results.map(x => x >> 0);
};
this.to_pixels = (size, dpi) => size * (dpi || settings("dpi")) / 25.1;
const create_canvas = this.create_canas = (html, width, height, callback) => {
const iframe = cache_box.appendChild(document.createElement("iframe")),
on_load_callback = event => {
const body = (iframe.contentDocument || iframe.contentWindow.document).body;
body.innerHTML = (`
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<title></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<style data-type="text/css" data-language="CSS3" data-rel="stylesheet" charset="utf-8">
html,body{margin : 0px;}
.iframe-box{
position : absolute;
width : ` + width + `px;
height : ` + height + `px;
}
</style>
</head>
<body>
<div class="iframe-box">` + html + `</div>
</body>
</html>
`);
new html2canvas(body, {
scale : 2,
backgroundColor : null,
width : width,
height : height
}).then(canvas => {
iframe.remove();
const uri = canvas.toDataURL("image/png", .9),
context = canvas.getContext("2d");
callback(canvas.toDataURL("image/png", .9));
});
};
iframe.setAttribute("style", "position:absolute;left:100%;top:100%;opacity:0;");
// iframe.addEventListener("load", on_load_callback);
setTimeout(on_load_callback, 50);
};
const date_format = this.date_format = this.datetime_format = this.time_format = (date, format) => {
const year = (date || (date = new Date())).getFullYear(),
month = date.getMonth() + 1,
day = date.getDate(),
hour = date.getHours(),
minute = date.getMinutes(),
second = date.getSeconds(),
timestamp = date.getTime(),
milliseconds = timestamp % 1000,
week_day = date.getDay();
return string_variables(format || (format = settings("date_format")), {
yyyy : ("0000" + year).slice(-4),
yy : ("00" + (year % 100)).slice(-2),
y : year,
year : year,
mmmm : months[month],
mmm : months[month].substr(0, 3),
mm : ("00" + month).slice(-2),
m : month,
month : month,
dd : ("00" + day).slice(-2),
d : day,
day : day,
hh : ("00" + hour).slice(-2),
h : hour,
hour : hour,
ii : ("00" + minute).slice(-2),
i : minute,
minute : minute,
ss : ("00" + second).slice(-2),
s : second,
second : second,
nnn : ("000" + milliseconds).slice(-3),
n : milliseconds,
milliseconds : milliseconds,
www : week_days[week_day],
ww : week_days[week_day].substr(0, 3),
w : week_day,
week_day : week_day,
weekday : week_day
});
};
const page_variables = (html, variables) => html.replace(/\{([^\{\}]+)\}/g, (...arguments) => {
if(variables[arguments[1]])
return variables[arguments[1]];
const matches = arguments[1].match(/^([^\:]+)(\:(.+)?)?$/);
if(matches)
switch(matches[1]){
case "date":
case "datetime":
case "time":
return date_format(new Date(), matches[3] ? matches[3].replace(/[\[\]]/g, (...arguments) => arguments[0] == "]" ? "]" : "[") : settings([matches[1] + "_format", "date_format"]))
};
return arguments[0];
});
const pdf_header_footer_create = (pdf, header, footer, margin, pages, callback, i) => {
const has_header = header,
has_footer = footer,
m = (has_header ? 1 : 0) + (has_footer ? 1 : 0);
if(!m || i > pages){
typeof callback == "function" && callback(pdf);
return;
};
let j = 0;
const end = () => {
if(++ j < m)
return;
pdf_header_footer_create(pdf, header, footer, margin, pages, callback, i + 1);
},
width = margin.page_width - margin.left - margin.right,
variables = {
page : i,
pages : pages
};
pdf.setPage(i);
has_header && create_canvas(page_variables(header[i % header.length], variables), width, margin.header_height, uri => {
pdf.addImage(uri, "PNG", margin.left, margin.header_top, width, margin.header_height);
end();
});
has_footer && create_canvas(page_variables(footer[i % footer.length], variables), width, margin.footer_height, uri => {
pdf.addImage(uri, "PNG", margin.left, margin.footer_top, width, margin.footer_height);
end();
});
};
this.create = (input, callback) => {
if(!input)
input = {};
else if(typeof input == "string")
input = {body : input};
else if(typeof input != "object")
input = {};
let body = `<div class="body">` + settings(["body", "html"], input, ``) + `</div>`,
header = settings(["header", "head"], input),
footer = settings(["footer", "foot"], input),
ended = false,
i = 0,
css = settings(["css", "styles", "style"], input),
margin_processed;
const variables = [{}, input.variables || {}, input],
type = settings("type", input),
margin = {
top : settings(["margin_top", "margin"], input),
left : settings(["margin_left", "margin"], input),
right : settings(["margin_right", "margin"], input),
bottom : settings(["margin_bottom", "margin"], input)
},
page_format = settings("page_format", input),
page_size = get_page_size(page_format),
body_size = {
width : page_size[0] - margin.left - margin.right,
height : page_size[1] - margin.top - margin.bottom
},
dpi = settings(["dpi", "ppp", "dpp"], input),
l = (
(header ? (header.push ? header : header = [header]).length : 0) +
(footer ? (footer.push ? footer : footer = [footer]).length : 0) +
1
),
end = () => {
if(ended || ++ i < l)
return;
ended = true;
body = string_variables(body, variables);
header && header.map(html => string_variables(html, variables));
footer && footer.map(html => string_variables(html, variables));
switch(type){
case "pdf":
const pdf = new window.jspdf.jsPDF({
unit : "px",
format : page_format,
hotfixes : ["px_scaling"]
}),
width = settings(["width", "width_" + page_format], input),
fonts_added = [];
let key;
css && css.forEach(string => string.replace(/font-family\s*\:\s*([^;]+)/g, (...arguments) => {
arguments[1].replace(/"([^"]+)"|'([^']+)'|([^\s]+)/g, (...subarguments) => {
fonts[key = subarguments[1] || subarguments[2] || subarguments[3]] && fonts[key].forEach(font => pdf.addFont(font[0], key, font[1]));
});
}));
pdf.html(body, {
callback : pdf => pdf_header_footer_create(pdf, header, footer, margin, pdf.internal.getNumberOfPages(), callback, 1),
// width : width,
margin : margin_processed,
autoPaging : "text",
html2canvas : {
letterRendering : 1,
allowTaint : true,
useCORS : true,
logging : true
}
});
break;
case "doc":
/*
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
xmlns='http://www.w3.org/TR/REC-html40'
xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns='http://www.w3.org/TR/REC-html40'
*/
callback(page_variables(string_variables((`
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
xmlns='http://www.w3.org/TR/REC-html40'
>
<head>
<title>` + (settings("title", input) || "") + `</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<style>
@page{
size : ` + page_format + `;
margin : ` + (
(margin.top / 10) + "cm " +
(margin.right / 10) + "cm " +
(margin.bottom / 10) + "cm " +
(margin.left / 10) + "cm"
) + `;
}
@page Section1{
/* Margin ---- */
/* Size ----- */
mso-page-orientation : landscape;
mso-header-margin : ` + (10 * settings("margin_header", input) / 10) + `cm; /* Why mm? */
mso-header : h1;
mso-footer-margin : ` + (10 * settings("margin_footer", input) / 10) + `cm; /* Why mm? */
mso-footer : f1;
}
div.Section1{page : Section1;}
</style>
<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Print</w:View>
<w:Zoom>100</w:Zoom>
<w:DoNotOptimizeForBrowser />
</w:WordDocument>
</xml><![endif]-->
</head>
<body>
<div class="Section1">
{header}
{footer}
{body}
</div>
</body>
</html>
`), [{
header : header && header.length ? `<div title="header" style="mso-element : header;" id="h1">` + header[0] + `</div>` : ``,
footer : footer && footer.length ? `<div title="footer" style="mso-element : footer;" id="f1">` + footer[0] + `</div>` : ``,
body : body
}].concat(variables)), {
page : `<sdfield type="PAGE" subtype="RANDOM" format="PAGE" style="mso-field-code : PAGE;">1</sdfield>`,
pages : `<sdfield type="DOCSTAT" subtype="PAGE" format="PAGE" style="mso-field-code : NUMPAGES;">1</sdfield>`
}));
break;
};
};
header && header.map(html => `<div class="header">` + html + `</div>`);
footer && footer.map(html => `<div class="header">` + html + `</div>`);
for(const key in variables[1])
if(variables[1][key] && typeof variables[1][key] == "object" && variables[1][key].type)
switch(variables[1][key].type){
case "grid":
case "table":
variables[0][key] = grid_to_html(variables[1][key], key);
break;
case "list":
variables[0][key] = list_to_html(variables[1][key], key);
break;
};
if(css)
!(css instanceof Array) && (css = [css]);
else
css = [];
switch(type){
case "pdf":
const header_height = header ? settings("header_height", input) : 0,
footer_height = footer ? settings("footer_height", input) : 0;
margin.header_top = margin.top + 0;
margin.header_height = header_height;
margin.header_bottom = page_size[1] - margin.top - header_height;
margin.footer_top = page_size[1] - margin.bottom - footer_height;
margin.footer_height = footer_height;
margin.footer_bottom = margin.bottom + 0;
margin.page_height = page_size[1];
margin.page_width = page_size[0];
header && (margin.top += header_height + settings("margin_header", input));
footer && (margin.bottom += footer_height + settings("margin_footer", input));
for(const key in margin)
margin[key] = dpi * margin[key] / 25.4;
margin_processed = [
margin.top,
margin.right,
margin.bottom,
margin.left
];
css.push(`
.header,.body,.footer{width : ` + ((dpi * page_size[0] / 25.4) - margin.left - margin.right) + `px;}
.header{
position : absolute;
top : 0px;
left : 0px;
}
`);
break;
case "doc":
break;
};
css_to_html(string_variables(body, variables), css, type, body_size, dpi, html => {body = html;end();});
header && header.forEach((html, i) => css_to_html(string_variables(html, variables), css, type, body_size, dpi, html => {header[i] = html;end();}));
footer && footer.forEach((html, i) => css_to_html(string_variables(html, variables), css, type, body_size, dpi, html => {footer[i] = html;end();}));
};
const get_uri_data = this.get_uri_data = (data, type) => {
if(typeof data == "string" && data.match(/^data\:[^,]+,[^,]+$/))
return data;
if(data instanceof Blob)
return URL.createObjectURL(data);
switch(type){
case "pdf":
return data.output("datauristring");
case "doc":
return "data:application/vnd.ms-word;charset=utf-8," + encodeURIComponent(data);
default:
return "data:application/octetstream;base64," + encodeURIComponent(btoa(typeof data == "object" ? JSON.stringify(data) : "" + data))
};
return null;
};
this.download = (data, file_name) => {
const anchor = cache_box.appendChild(document.createElement("a"));
anchor.setAttribute("download", file_name);
anchor.setAttribute("target", "_blank");
anchor.setAttribute("href", get_uri_data(data, file_name.match(/\.([^\.]+)$/)[1].toLowerCase()));
anchor.click();
anchor.remove();
// window.open(get_uri_data(data, file_name.match(/\.([^\.]+)$/)[1].toLowerCase()), "_blank");
};
const add_fonts = this.add_fonts = array => array && array.push && array.forEach(font => {
if(!fonts[font[0]])
fonts[font[0]] = [[font[1], font[2]]];
else{
let i;
const exists = fonts[font[0]].some((source, j) => {
if(source[1] == font[2]){
i = j;
return true;
};
});
if(exists)
fonts[font[0]][i][0] = font[1];
else
fonts[font[0]].push([font[1], font[2]]);
};
});
const construct = () => {
week_days = settings("week_days");
months = settings("months");
["default_fonts", "fonts"].forEach(key => add_fonts(settings(key)));
settings("autostart") && self.start();
};
construct();
};