From b4b8a4f019993cb3a66f9d08891650c818bc0251 Mon Sep 17 00:00:00 2001 From: KyMAN <0kyman0@gmail.com> Date: Wed, 31 Jan 2024 14:13:33 +0100 Subject: [PATCH] fix: Migrating project to the new Gitea Host. --- .gitignore | 7 + HTML/base.jsreports.html | 183 +++++ Public/.htaccess | 1 + Public/ecma/JSReports.ecma.js | 908 +++++++++++++++++++++ Public/git_update.php | 4 + Public/test.html | 164 ++++ Public/wmd.php | 6 + Public/wmd_scripts.php | 26 + WMD/dev/ECMAScript/index.w.md | 24 + WMD/dev/Public/ecma/JSReports.ecma.js.w.md | 549 +++++++++++++ WMD/dev/index.w.md | 55 ++ WMD/es/bugs.w.md | 122 +++ WMD/es/index.w.md | 38 + WMD/es/notes.w.md | 176 ++++ WMD/es/project.w.md | 29 + WMD/es/projects.w.md | 67 ++ WMD/es/targets.w.md | 51 ++ WMD/index.w.md | 40 + 18 files changed, 2450 insertions(+) create mode 100755 .gitignore create mode 100755 HTML/base.jsreports.html create mode 100755 Public/.htaccess create mode 100755 Public/ecma/JSReports.ecma.js create mode 100755 Public/git_update.php create mode 100755 Public/test.html create mode 100755 Public/wmd.php create mode 100755 Public/wmd_scripts.php create mode 100755 WMD/dev/ECMAScript/index.w.md create mode 100755 WMD/dev/Public/ecma/JSReports.ecma.js.w.md create mode 100755 WMD/dev/index.w.md create mode 100755 WMD/es/bugs.w.md create mode 100755 WMD/es/index.w.md create mode 100755 WMD/es/notes.w.md create mode 100755 WMD/es/project.w.md create mode 100755 WMD/es/projects.w.md create mode 100755 WMD/es/targets.w.md create mode 100755 WMD/index.w.md diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..de8b9f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +Public/data +PHP/JSReports.Secrets.php +JSReports.apache2.conf +Public/index.html +Public/dev +Public/es +JSON/html.files.json diff --git a/HTML/base.jsreports.html b/HTML/base.jsreports.html new file mode 100755 index 0000000..2b8cf3c --- /dev/null +++ b/HTML/base.jsreports.html @@ -0,0 +1,183 @@ + + + + {title} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ + + + JSReports + + JSReports + +

+ +
+
+
+ Menu + + +
+
+ Content +
{content}
+
+
+ Files + + +
+
+ + + diff --git a/Public/.htaccess b/Public/.htaccess new file mode 100755 index 0000000..81d9bac --- /dev/null +++ b/Public/.htaccess @@ -0,0 +1 @@ +Header set Access-Control-Allow-Origin "*" diff --git a/Public/ecma/JSReports.ecma.js b/Public/ecma/JSReports.ecma.js new file mode 100755 index 0000000..73b290b --- /dev/null +++ b/Public/ecma/JSReports.ecma.js @@ -0,0 +1,908 @@ +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 = (` + + + + `); + + grid.header.forEach((header, j) => html += ``); + html += (` + + + + `); + grid.body.forEach((row, i) => { + html += ``; + row.forEach((value, j) => html += ``); + html += ``; + }); + html += (` + +
` + header + `
` + value + `
+ `); + + 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 += `
  • ` + (typeof item == "object" ? item[0] + list_to_html(item[1]) : item) + `
  • `); + html += ``; + + 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 + `
    `; + + }; + + 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 = (` + + + + + + + + + +
    ` + 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 = `
    ` + settings(["body", "html"], input, ``) + `
    `, + 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((` + + + + ` + (settings("title", input) || "") + ` + + + + + + +
    + {header} + {footer} + {body} +
    + + + `), [{ + header : header && header.length ? `
    ` + header[0] + `
    ` : ``, + footer : footer && footer.length ? `
    ` + footer[0] + `
    ` : ``, + body : body + }].concat(variables)), { + page : `1`, + pages : `1` + })); + break; + }; + + }; + + header && header.map(html => `
    ` + html + `
    `); + footer && footer.map(html => `
    ` + html + `
    `); + + 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(); + +}; diff --git a/Public/git_update.php b/Public/git_update.php new file mode 100755 index 0000000..0879a28 --- /dev/null +++ b/Public/git_update.php @@ -0,0 +1,4 @@ +&1"); diff --git a/Public/test.html b/Public/test.html new file mode 100755 index 0000000..752436c --- /dev/null +++ b/Public/test.html @@ -0,0 +1,164 @@ + + + + JSReports - Tests + + + + + + + + + + + + + + + + diff --git a/Public/wmd.php b/Public/wmd.php new file mode 100755 index 0000000..d9d76b2 --- /dev/null +++ b/Public/wmd.php @@ -0,0 +1,6 @@ + "update_scripts", + "author" => "KyMAN", + "project" => "JSReports", + "class" => "JSReports", + "object" => "jsreports", + "url" => "https://jsreports.k3y.pw", + "project_author" => "KyMAN", + "key_words" => "jsreports,js,report,ecma,pdf,doc,csv,kyman,developt,desarrollo,documentacion,doc", + "logo" => "/images/JSReports.png", + "language" => "es", + "wmd_file" => "/../WMarkDown/HTML/script.w.md", + "wmd_file_empty" => "/../WMarkDown/HTML/file.w.md", + "ignore_script_paths" => [ + "/Public/data", + "/Public/git_update.php", + "/Public/wmd.php", + "/Public/wmd_scripts.php" + ], + "only" => "/Public" + ], JSReports\Secrets::wmarkdown)); diff --git a/WMD/dev/ECMAScript/index.w.md b/WMD/dev/ECMAScript/index.w.md new file mode 100755 index 0000000..baa22a8 --- /dev/null +++ b/WMD/dev/ECMAScript/index.w.md @@ -0,0 +1,24 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# ECMAScript + +[[header_level 0]] +[[include /WMD/dev/Public/ecma/JSReports.ecma.js.w.md]] + + + +[[html_data { + "title" : "ECMAScript - JSReports", + "url" : "https://jsreports.k3y.pw/dev/ECMAScript/index.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,developt,desarrollo,documentacion,doc,developt,desarrollo,programación,ecmascript", + "description" : "Parte ECMAScript del JSReports.", + "project" : "JSReports", + "logo" : "/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/dev/Public/ecma/JSReports.ecma.js.w.md b/WMD/dev/Public/ecma/JSReports.ecma.js.w.md new file mode 100755 index 0000000..3f4411e --- /dev/null +++ b/WMD/dev/Public/ecma/JSReports.ecma.js.w.md @@ -0,0 +1,549 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# JSReports.ecma.js + +```txt +/Public/ecma/JSReports.ecma.js +``` + +## [[plain JSReports.event_execute]] + +[[wdoc +Método object. +@name JSReports.event_execute +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 8278db1e610a100e5d356a52280cc082 +#key - optional Parámetro key +#return - - Retorno. +]] + +## [[plain JSReports.event_add]] + +[[wdoc +Método object. +@name JSReports.event_add +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 0c176da24fa7ae3cb649495f8e7170d8 +#key - optional Parámetro key +#method - optional Parámetro method +#return - - Retorno. +]] + +## [[plain JSReports.event_remove]] + +[[wdoc +Método object. +@name JSReports.event_remove +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 19d4a9003d7c5d18ecaaea69096d8af0 +#key - optional Parámetro key +#i - optional Parámetro i +#return - - Retorno. +]] + +## [[plain JSReports.is_html_item]] + +[[wdoc +Método object. +@name JSReports.is_html_item +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 9fc6e2286fc35144ae5d31e9f90223a0 +#item - optional Parámetro item +#return - - Retorno. +]] + +## [[plain JSReports.default_value]] + +[[wdoc +Método object. +@name JSReports.default_value +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash a1841f42c4352bb7f9f7bb87f89ff6fb +#_default - optional Parámetro _default +#nulls - optional Parámetro nulls +#return - - Retorno. +]] + +## [[plain JSReports.settings]] + +[[wdoc +Método object. +@name JSReports.settings +@see JSReports.default_value +@see JSReports.settings +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash aca8a9716fee6aef64d6753573aebf61 +#names - optional Parámetro names +#inputs - optional Parámetro inputs +#_default - optional Parámetro _default +#nulls - optional Parámetro nulls +#return - - Retorno. +]] + +## [[plain JSReports.threads_method]] + +[[wdoc +Método object. +@name JSReports.threads_method +@see JSReports.event_execute +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access private +@hash bdc0d47954df34f8c7dd34886abb484b +#return - - Retorno. +]] + +## [[plain JSReports.threads_start]] + +[[wdoc +Método object. +@name JSReports.threads_start +@see JSReports.settings +@see JSReports.threads_method +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 8ddfcc5b5bc311360f29b185dce9cd19 +#frames_per_second - optional Parámetro frames_per_second +#return - - Retorno. +]] + +## [[plain JSReports.threads_stop]] + +[[wdoc +Método object. +@name JSReports.threads_stop +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash c1b6d79c278d28a090faf96255fa0c34 +]] + +## [[plain JSReports.threads_add]] + +[[wdoc +Método object. +@name JSReports.threads_add +@see JSReports.event_add +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash a8bcfab6b51e3d71c29dfe4489f1a2ea +#method - optional Parámetro method +#return - - Retorno. +]] + +## [[plain JSReports.threads_remove]] + +[[wdoc +Método object. +@name JSReports.threads_remove +@see JSReports.event_remove +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 2502fd5b998c2aa8c8ef113766274944 +#i - optional Parámetro i +#return - - Retorno. +]] + +## [[plain JSReports.preload]] + +[[wdoc +Método object. +@name JSReports.preload +@see JSReports.is_html_item +@see JSReports.settings +@see JSReports.threads_add +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 78825cc3c12f69f2ce9e0dbb365032e3 +#selector - optional Parámetro selector +#callback - optional Parámetro callback +]] + +## [[plain JSReports.ready]] + +[[wdoc +Método object. +@name JSReports.ready +@see JSReports.event_execute +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access private +@hash 24173da9f3087d1dc7dd6cfb091e1973 +#position - optional Parámetro position +]] + +## [[plain JSReports.start]] + +[[wdoc +Método object. +@name JSReports.start +@see JSReports.threads_start +@see JSReports.settings +@see JSReports.preload +@see JSReports.ready +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 7a9f7395ead121483d8fff795eec1c1f +]] + +## [[plain JSReports.on_ready]] + +[[wdoc +Método object. +@name JSReports.on_ready +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash b10a8f8510b1fdd31af34e4742531d68 +#method - optional Parámetro method +#return - - Retorno. +]] + +## [[plain JSReports.string_variables]] + +[[wdoc +Método object. +@name JSReports.string_variables +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash baaa8e283a18d68f6e9af7bb5fa4cbbe +#string - optional Parámetro string +#variables - optional Parámetro variables +#_default - optional Parámetro _default +]] + +## [[plain JSReports.base64_to_blob]] + +[[wdoc +Método object. +@name JSReports.base64_to_blob +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash b9ca1772f19dd57db9bedc5678ed79e5 +#uri - optional Parámetro uri +#type - optional Parámetro type +#return - - Retorno. +]] + +## [[plain JSReports.hash]] + +[[wdoc +Método object. +@name JSReports.hash +@see JSReports.settings +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 0e8da659a099929c4de6a1f107c44d8c +#return - - Retorno. +]] + +## [[plain JSReports.grid_to_html]] + +[[wdoc +Método object. +@name JSReports.grid_to_html +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 667df7e5df63dd419bf9465b12f221a1 +#grid - optional Parámetro grid +#name - optional Parámetro name +#return - - Retorno. +]] + +## [[plain JSReports.list_to_html]] + +[[wdoc +Método object. +@name JSReports.list_to_html +@see JSReports.settings +@see JSReports.list_to_html +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash d0310359b0d5fbe909db8f3968c63972 +#list - optional Parámetro list +#name - optional Parámetro name +#return - - Retorno. +]] + +## [[plain JSReports.css_to_html]] + +[[wdoc +Método object. +@name JSReports.css_to_html +@see JSReports.hash +@see JSReports.preload +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash ca5cbc79e2bf66ca5b2b3fb1d5390cea +#html - optional Parámetro html +#css - optional Parámetro css +#type - optional Parámetro type +#body_size - optional Parámetro body_size +#dpi - optional Parámetro dpi +#callback - optional Parámetro callback +]] + +## [[plain JSReports.get_page_size]] + +[[wdoc +Método object. +@name JSReports.get_page_size +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 0c9acc181031029511c870013794933e +#format - optional Parámetro format +#return - - Retorno. +]] + +## [[plain JSReports.to_pixels]] + +[[wdoc +Método object. +@name JSReports.to_pixels +@see JSReports.settings +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 834fd27f6c5fad1286ac1d4f2686a685 +#size - optional Parámetro size +#dpi - optional Parámetro dpi +#return - - Retorno. +]] + +## [[plain JSReports.create_canas]] + +[[wdoc +Método object. +@name JSReports.create_canas +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash e590bf71f37824d9ccfad63f9d5d1b18 +#html - optional Parámetro html +#width - optional Parámetro width +#height - optional Parámetro height +#callback - optional Parámetro callback +]] + +## [[plain JSReports.time_format]] + +[[wdoc +Método object. +@name JSReports.time_format +@see JSReports.string_variables +@see JSReports.settings +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 204420143766456a0655f90e88bde2a8 +#date - optional Parámetro date +#format - optional Parámetro format +]] + +## [[plain JSReports.page_variables]] + +[[wdoc +Método object. +@name JSReports.page_variables +@see JSReports.settings +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access private +@hash 0e1b0f139196df893613aac593e29e3c +#html - optional Parámetro html +#variables - optional Parámetro variables +#return - - Retorno. +]] + +## [[plain JSReports.pdf_header_footer_create]] + +[[wdoc +Método object. +@name JSReports.pdf_header_footer_create +@see JSReports.pdf_header_footer_create +@see JSReports.page_variables +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access private +@hash fc6d493a044a62726024d64c9cdaa4f0 +#pdf - optional Parámetro pdf +#header - optional Parámetro header +#footer - optional Parámetro footer +#margin - optional Parámetro margin +#pages - optional Parámetro pages +#callback - optional Parámetro callback +#i - optional Parámetro i +]] + +## [[plain JSReports.create]] + +[[wdoc +Método object. +@name JSReports.create +@see JSReports.settings +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash d8eec2408d0579c21dfaed249e09d2c9 +#input - optional Parámetro input +#callback - optional Parámetro callback +]] + +## [[plain JSReports.get_uri_data]] + +[[wdoc +Método object. +@name JSReports.get_uri_data +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash f4644a2029a63c4358ff2c669cc04ab8 +#data - optional Parámetro data +#type - optional Parámetro type +#return - - Retorno. +]] + +## [[plain JSReports.download]] + +[[wdoc +Método object. +@name JSReports.download +@see JSReports.get_uri_data +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 4f44d8e3a5538fff046fd56976784a58 +#data - optional Parámetro data +#file_name - optional Parámetro file_name +]] + +## [[plain JSReports.add_fonts]] + +[[wdoc +Método object. +@name JSReports.add_fonts +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access public +@hash 3e46c209a2c978863975828939679f6c +#array - optional Parámetro array +#return - - Retorno. +]] + +## [[plain JSReports.construct]] + +[[wdoc +Método object. +@name JSReports.construct +@see JSReports.settings +@see JSReports.add_fonts +@see JSReports.start +@lang ECMAScript +@author KyMAN +@since 20220422 +@version 20220422 +@access private +@hash 3843a081dceb29470cdbf51afab923a8 +]] + +[[html_data { + "title" : "JSReports.ecma.js - JSReports", + "url" : "https://jsreports.k3y.pw/Public/ecma/JSReports.ecma.js.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,developt,desarrollo,documentacion,doc,developt,desarrollo,programación,cma", + "description" : "JSReports.ecma.js del JSReports.", + "project" : "JSReports", + "logo" : "/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/dev/index.w.md b/WMD/dev/index.w.md new file mode 100755 index 0000000..d9fd530 --- /dev/null +++ b/WMD/dev/index.w.md @@ -0,0 +1,55 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] + +# ECMAScript + +- [/dev/ECMAScript#JSReports-ecma-js-2 /Public/ecma/JSReports.ecma.js] + - [/dev/ECMAScript#JSReports-event-execute-2 JSReports.event\_execute] + - [/dev/ECMAScript#JSReports-event-add-2 JSReports.event\_add] + - [/dev/ECMAScript#JSReports-event-remove-2 JSReports.event\_remove] + - [/dev/ECMAScript#JSReports-is-html-item-2 JSReports.is\_html\_item] + - [/dev/ECMAScript#JSReports-default-value-2 JSReports.default\_value] + - [/dev/ECMAScript#JSReports-settings-2 JSReports.settings] + - [/dev/ECMAScript#JSReports-threads-method-2 JSReports.threads\_method] + - [/dev/ECMAScript#JSReports-threads-start-2 JSReports.threads\_start] + - [/dev/ECMAScript#JSReports-threads-stop-2 JSReports.threads\_stop] + - [/dev/ECMAScript#JSReports-threads-add-2 JSReports.threads\_add] + - [/dev/ECMAScript#JSReports-threads-remove-2 JSReports.threads\_remove] + - [/dev/ECMAScript#JSReports-preload-2 JSReports.preload] + - [/dev/ECMAScript#JSReports-ready-2 JSReports.ready] + - [/dev/ECMAScript#JSReports-start-2 JSReports.start] + - [/dev/ECMAScript#JSReports-on-ready-2 JSReports.on\_ready] + - [/dev/ECMAScript#JSReports-string-variables-2 JSReports.string\_variables] + - [/dev/ECMAScript#JSReports-base64-to-blob-2 JSReports.base64\_to\_blob] + - [/dev/ECMAScript#JSReports-hash-2 JSReports.hash] + - [/dev/ECMAScript#JSReports-grid-to-html-2 JSReports.grid\_to\_html] + - [/dev/ECMAScript#JSReports-list-to-html-2 JSReports.list\_to\_html] + - [/dev/ECMAScript#JSReports-css-to-html-2 JSReports.css\_to\_html] + - [/dev/ECMAScript#JSReports-get-page-size-2 JSReports.get\_page\_size] + - [/dev/ECMAScript#JSReports-to-pixels-2 JSReports.to\_pixels] + - [/dev/ECMAScript#JSReports-create-canas-2 JSReports.create\_canas] + - [/dev/ECMAScript#JSReports-time-format-2 JSReports.time\_format] + - [/dev/ECMAScript#JSReports-page-variables-2 JSReports.page\_variables] + - [/dev/ECMAScript#JSReports-pdf-header-footer-create-2 JSReports.pdf\_header\_footer\_create] + - [/dev/ECMAScript#JSReports-create-2 JSReports.create] + - [/dev/ECMAScript#JSReports-get-uri-data-2 JSReports.get\_uri\_data] + - [/dev/ECMAScript#JSReports-download-2 JSReports.download] + - [/dev/ECMAScript#JSReports-add-fonts-2 JSReports.add\_fonts] + - [/dev/ECMAScript#JSReports-construct-2 JSReports.construct] + + +[[html_data { + "title" : "Código - JSReports", + "url" : "https://jsreports.k3y.pw/dev/index.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,developt,desarrollo,documentacion,doc,developt,desarrollo,programación,todo,all", + "description" : "Parte Todo del JSReports.", + "project" : "JSReports", + "logo" : "/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/es/bugs.w.md b/WMD/es/bugs.w.md new file mode 100755 index 0000000..5a6da67 --- /dev/null +++ b/WMD/es/bugs.w.md @@ -0,0 +1,122 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# Bugs + +En esta sección se catalogarán todos los Bugs y el estado conforme a si están o no arreglados o si +se están tratando. + +## Cabeceras y pies dispares en UDF + +Las cabeceras y pies de página salen en las páginas impares en UDF. El problema recae principalmente +en que los etiquetados y marcas de MS no son compatibles con las de UDF, siendo para UDF el +'title="header"' para la cabecera y el 'title="footer"' para el pie; mientras que en MS sería el +atributo Style "mso-element:header;" para la cabecera y "mso-elemento:footer;" para el pie. Está +globalizado, pero el método UDF sólo muestra las cabeceras y los pies en las páginas impares. + +- [ ] Arreglar el fallo para que salgan en todas las páginas. + +Hay una pseudosolución que aportaron en la respuesta del Link que se muestra a continuación se +muestra una pseudosolución (Digo pseudo porque no es una cabecera ni pié real, sino que se usa una +tabla que contiene ambas cosas la cual repite su THEAD y su TFOOT en todas las páginas) pero al no +ser una cabecera y pié reales no lo establecí, pero decir que en caso de extrema necesidad, ésta +puede ser aplicada perfectamente. + +https://stackoverflow.com/questions/1360869/how-to-use-html-to-print-header-and-footer-on-every-printed-page-of-a-document#answer-51371081 + +## Problemas cabeceras y piés PDF + +El jsPDF no fue diseñado para trabajar en profundidad el HTML de hecho, no es capaz ni de +interpretar CSS ni de adjuntar las fuentes de forma autónoma, pero el problema viene a la hora de +establecer un elemento HTML pues, aunque establezcas la página donde quieras establecerlo, éste +siempre irá a la primera página, y si estableces un margen o posición "top" muy alto, éste +desaparece si no es nativo para estar ahí. El HTML se superpondrá a lo que ya hay en el documento y +no permite establecer márgenes diferentes a distintos HTML, por lo que el tema de las cabeceras +queda totalmente descartado mediante HTML nativo. + +- [X] Conseguir un sistema que permita generar cabeceras y piés de página contra HTML y CSS. +- [ ] Probar el sistema de impresión HTML de CSS para establecer una tabla que por página repita su +THEAD y su TFOOT, como la trampa para establecer cabeceras que encontré para DOCs. + +> [[! important IMPORTANTE]]: Actualmente, este sistema funciona pero es a partir de la creación de +una imagen contra el HTML y CSS dado lo que impide seleccionar texto entre otros problemas. No me +preocupan los sistemas que migran de PDF a DOC por los OCR. + +> [[! note NOTA]]: Para arreglar este problema se optó por hacer uso de la dependencia del propio +jsPDF: html2canvas, y de ahí se extrae una imagen en URI Base64 que es la que se usa para dichos +fines. + +## Problemas con CSS + +En los documentos DOC, la etiqueta STYLE que contiene el CSS, tiene órdenes y sentencias muy +específicas que no pueden ser flexibilizadas por lo que hay que hacer una adaptación de la misma +para que funcionen. + +- [X] Crear adaptación para que se generen. + +Básicamente se reutilizó el sistema hecho para los PDF. + +## Corregir tamaños IMG + +Las imágenes, en os documentos DOC tienen el problema del valor de atributo "width" y "height" auto, +que cogen como valor su ancho o alto, consecutivamente. + +- [X] Conseguir proporcionar las imágenes. + +Para arreglar dicho fallo se hice un análisis del CSS contra las imágenes en su precarga y +establecer un tamaño relativo con respecto al formato de página, tamaño de la misma y el tamaño de +la imagen. + +## Tamaños de tabla + +En los DOC, las tablas no hacen caso de los atributos de tamaño de CSS, requiriendo de hacer uso del +atributo WIDTH. + +Por otro lado, las celdas tampoo hacen caso de su ancho, teniendo que usar la etiqueta COLGROUP y +sus subetiquetas COL. + +- [X] Migrar el ancho en CSS al atributo WIDTH de la tabla. +- [X] Migrar el ancho de las columnas a los COL. +- [-] Corregir la porcentualidad de los COL. + +> [[! important IMPORTANTE]]: Los COL, en los DOC UDF ignora la unidad del atributo y no respeta la +proporción de peso, quedando sobre una proporción a 50000. Automáticamente lo tramita desde los DPI +en medidas por pixel; y por el tamaño de página en mm, cm, in, etc; así como por los propios +porcentajes. Creo que es algo que hay que mejorar, pero que para salir del paso llega. + +## Medidas mm en DOC UDF + +Cuando tratabajamos los márgenes CSS de las cabeceras y los pies de página, éstos se establecen en +mm de forma forzada aunque le pongas otra unidad de medida. + +> [[! note NOTA]]: Al ser un atributo CSS especial para MS puede ser que se condicione forzadamente +en mm? No hay información a penas acerca de ello. + +- [ ] Arreglar el Bug, o al menos, adaptarlo para que salga en otras unidades establecidas en CSS. + +> [[! note NOTA]]: Actualmente está trabajando en mm, de la misma forma que trabaja esta librería. + +## PDF en Chrome + +Por algún motivo, en Chrome no crea el PDF. Queda como totalmente apagado y sin terminar el proceso. + +- [X] Arreglar el Bug. + +El Bug parece ser que era porque el evento OnLoad del IFRAME que gestiona los html2canvas no existe +en Chrome salvo que éste venga con una URL, por lo que se decidió hacer un Timeout para solventar la +precarga del objeto. + +[[html_data { + "title" : "JSReports - Bugs", + "url" : "https://jsreports.k3y.pw/es/bugs.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación,bugs,errores,errors", + "description" : "Bugs del proyecto JSReports.", + "project" : "Bugs", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/es/index.w.md b/WMD/es/index.w.md new file mode 100755 index 0000000..9a7354e --- /dev/null +++ b/WMD/es/index.w.md @@ -0,0 +1,38 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# JSReports + +Este proyecto está orientado a crear Reports (Informes) directamente desde JS cliente desde un +navegador. Dichos informes se entiende como resultados de información en texto como PDF, DOC, etc. +Así como tablas de datos. + +[[header_level 0]] +[[include /WMD/es/project.w.md]] + +[[header_level 0]] +[[include /WMD/es/projects.w.md]] + +[[header_level 0]] +[[include /WMD/es/notes.w.md]] + +[[header_level 0]] +[[include /WMD/es/bugs.w.md]] + +[[header_level 0]] +[[include /WMD/es/targets.w.md]] + +[[html_data { + "title" : "JSReports - Documentación", + "url" : "https://jsreports.k3y.pw/es", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación", + "description" : "Documentación del proyecto JSReports.", + "project" : "Documentación", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/es/notes.w.md b/WMD/es/notes.w.md new file mode 100755 index 0000000..52ffb6c --- /dev/null +++ b/WMD/es/notes.w.md @@ -0,0 +1,176 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# Notas + +Notas para no olvidarme del proyecto. + +El proyecto se basa en una librería ECMA/JS la cual se llama JSReports como nombre de clase. Hay que +crear un objecto JSReports para poder trabajar con ella. En el caso de PDF depende de las librerías: + +- [https://cdn.k3y.pw/js/html2canvas.min.js] +- [https://cdn.k3y.pw/js/jspdf.umd.min.js] +- [https://cdn.k3y.pw/js/purify.min.js] + +Para poder empezar a trabajar con esta librería hay que esperar asíncronamente a que termine de +cargar mediante un Callback "on_ready" + +```js +(js_reports = new JSReports(/* PARAMETROS DE ENTRADA */)).on_ready(() => console.log("Ya terminó de cargar xD")); +``` + +> [[! note NOTA]]: La librería requiere de un sitio donde poner componentes de forma temporal a modo +de caché. No le vale un DocumentFragment. Si no se le establece se pondrá por defecto BODY. + +# PDF y DOC + +El trabajo con esta librería cara los PDF y DOC es exactamente igual. Hay que llamar a un método +llamado "create" el cual permite crear este tipo de documentos. La librería se centra en que crees +un HTML4 y CSS2, aunque pueden ser adjuntadas cosas de HTML5 y XHTML, así como algunos parámetros +CSS3 y customizados cara cualquier a de las dos plataformas. La idea es construir plantillas para +cabeceras, pies y cuerpos en HTML y una única hoja de estilos general en CSS, lo que cubriría el 99% +del informe, luego hay ciertos parámetros que son necesarios establecer mediante valores. + +Con esta información tenemos como parámetros de entrada un único valor que vendrá siendo un +diccionario el cual tiene los siguientes elementos: + +> [[! note NOTA]]: Todas las medidas se toma en mm (Milímetros). + +- **header**: Cabecera HTML. +- **body**: Cuerpo HTML. +- **footer**: Pié HTML. +- **css**: Estilos CSS. +- **type**: Extensión que determina si es "doc" o "pdf". +- **margin**: Margen general para cualquier lado. +- **margin_top**: Margen superior. +- **margin_right**: Margen derecho. +- **margin_bottom**: Margen inferior. +- **margin_left**: Margen izquierdo. +- **variables**: Variables para cubrir dentro de los HTML. +- **header_height**: Alto de la cabecera. +- **footer_height**: Alto del pié. +- **margin_header**: Margen de la cabecera. +- **margin_footer**: Margen del pié. +- **dpi**: DPI para marcar tamaños digitales en PX. +- **page_format**: Formato de página (A4, A3, A5, C5, Letter (L), etc.); o tamaño (alto y ancho). + +El formato PDF requiere de embedar las fuentes con las que se vaya a trabajar en formato TTF, que es +el formato por defecto cara los OS. Dicho formato requiere de un archivo por estilo (Regular o +normal, Light, Bold, Italic, etc). Para embedar fuentes es necesario cubrir la variable "fonts" en +el diccionario de parámetros de entrada del objeto y se compone de un Array bidimensional donde el +primer nivel es conjunto de fuentes y el segundo se compone de: + +0. Nombre de la fuente. +0. Link del estilo. +0. Nombre del estilo. + +En ambos casos, las imágenes se embedarán mediante URI Base64, pasando a formar parte del documento. +Las imágenes, por defecto, suelen estar protegidas por CORS. Para saltarse dicha restricción es +importante hacer uso de un Proxy. Para establecer el Proxy hemos de establecer el parámetro global +"proxy" que vendrá siendo una URL contra el Proxy donde la variable String "{url}" determinará donde +colocar la URL de la imagen. + +```js +js_reports = new JSReports({ + proxy : "https://proxycors.local/api/DHkwPBhzp78Gz8g3BmG4VFnDgnt5kU9J6XQPjWMGDKwjr6s3f9nV7545B/{url}" +}) +``` + +> [[! note NOTA]]: Si el Proxy no retorna las cabeceras del CORS, éste no servirá de nada. Se puede +hacer uso del proyecto [https://proxycors.k3y.pw/ ProxyCORS], proyecto en el que está basado el +ejemplo también desarrollado por KyMAN. El Git del proyecto es [https://git.k3y.pw/KyMAN/ProxyCORS]. + +> [[! important IMPORTANTE]]: El link del ProxyCORS posiblemente no funcione por el hecho de que con +dicho Hash podrían usar mi servidor como salto anónimo para saltarse el CORS entre otros fines por +lo que el Hash quede deshabilitado. + +También se le pueden agregar componentes especiales al documento como tablas o listas programas +directamente como objetos o Arrays a partir de un objeto que determina su tipo y el contenido del +mismo. A continuación se titularán los tipos de objetos especiales que hay actualmente. + +## Tablas (Grids) + +Los documentos DOC y PDF permiten la generación de tablas dinámicas a partir de la idea de un Grid, +es decir, un objeto que determina la cabecera y los datos y automáticamente, el programa embedará +una tabla con dichos datos. La estructura del objeto es la siguiente: + +- **type**: Tipo (puede ser "table" o "grid"). +- **header** : Array de textos, cada uno será la cabecera de esa columna concreta. +- **body**: Cuerpo de la tabla o datos. Array bidimensional con los valores por cada tupla y columna. + +Un ejemplo de una tabla puede ser el siguiente: + +```js +const table = { + type : "table", + header : ["Cabecera 1", "Cabecera 2", "Cabecera 3", "...", "Cabecera N"], + body : [ + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"], + ["Valor 1", "Valor 2", "Valor 3", "...", "Valor N"] + ] +}; +``` + +## Listas + +Los documentos DOC y PDF permiten la generación de listas dinámicas a partir de un Array el cual +puede anidar otros Array para hacer Listas de múltiples niveles. Admiten tantos listas ordenadas +como desordenadas, y su estructura es la siguiente: + +- **type**: Tipo (Siempre será "list"), +- **mode**: El modo en que se mostrarán los datos. Éste puede ser: + - *ol* o *ordered*: Para mostrar los datos con un valor que representa su posición autoincremental. + - *ul* o *unordered*: Para mostrar los datos con puntos, guiones o como se establezca por CSS. +- **start**: Para los elementos ordenados autoincrementalmente, valor numérico de inicio. +- **items**: Array de elementos ordenados. Puede contener objetos que anidan otras listas. + +Un ejemplo de una tabla puede ser el siguiente: + +```js +const list = { + type : "list", + mode : "ordered", + start : 12, + items : [ + "cosa 1", + "cosa 2", + "cosa 3", + "...", + ["jojo", { + mode : "unordered", + items : [ + "pasa A", + ["pasa B", { + items : [ + "otro xD" + ] + }], + "pasa C" + ] + }], + "juas", + "jiji" + ] +}; +``` + +[[html_data { + "title" : "JSReports - Notas", + "url" : "https://jsreports.k3y.pw/es/notes.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación,notas", + "description" : "Notas del proyecto JSReports.", + "project" : "JSReports", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/es/project.w.md b/WMD/es/project.w.md new file mode 100755 index 0000000..5e27a1b --- /dev/null +++ b/WMD/es/project.w.md @@ -0,0 +1,29 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# Proyecto + +El proyecto viene siendo una librería Core que permite, desde un cliente JS (Navegador), junto con +sus dependencias, en caso de requerirlo, crear informes en múltiples formatos como PDF y DOC, +pasando como formato visual HTML y CSS, así como generación de archivos multiplataforma compatibles +con Excel y Calc como es el formato CSV. También se baraja la idea de poder gestionar la descarga de +información directa en XML, JSON, etc. + +La librería final es la siguiente: + +https://jsreports.k3y.pw/ecma/JSReports.ecma.js + +[[html_data { + "title" : "JSReports - Proyecto", + "url" : "https://jsreports.k3y.pw/es/project.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación,proyecto,descripción", + "description" : "Descripción del proyecto JSReports.", + "project" : "Proyecto", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/es/projects.w.md b/WMD/es/projects.w.md new file mode 100755 index 0000000..58db781 --- /dev/null +++ b/WMD/es/projects.w.md @@ -0,0 +1,67 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# Proyectos y dependencias + +Este proyecto depende de una serie de librerías externas las cuales son: + +[[links_group [{ + "images" : [], + "link" : "https://github.com/cure53/DOMPurify", + "text" : "DOMPurify" +}, { + "images" : ["data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNTZweCIgaGVpZ2h0PSI1NnB4IiB2aWV3Qm94PSIwIDAgNTYgNTYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iUHJvcG9zYWwtLS1TdWtodW12aXQtU2V0IiBmaWxsPSIjRkZGRkZGIj4KICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDAwMDAwLCAzLjAwMDAwMCkiPgogICAgICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwIiBmaWxsLXJ1bGU9Im5vbnplcm8iPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik00LDEyIEw0LDQ2IEwzNy4wMjMyNTU4LDQ2IEwzNy4wMjMyNTU4LDEyIEw0LDEyIFogTTIsOCBMMzkuMDIzMjU1OCw4IEM0MC4xMjc4MjUzLDggNDEuMDIzMjU1OCw4Ljg5NTQzMDUgNDEuMDIzMjU1OCwxMCBMNDEuMDIzMjU1OCw0OCBDNDEuMDIzMjU1OCw0OS4xMDQ1Njk1IDQwLjEyNzgyNTMsNTAgMzkuMDIzMjU1OCw1MCBMMiw1MCBDMC44OTU0MzA1LDUwIDEuMzUyNzA3NWUtMTYsNDkuMTA0NTY5NSAtMS4yMzI1OTUxNmUtMzEsNDggTC0yLjIyMDQ0NjA1ZS0xNiwxMCBDLTMuNTczMTUzNTVlLTE2LDguODk1NDMwNSAwLjg5NTQzMDUsOCAyLDggWiIgaWQ9IlJlY3RhbmdsZSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMiw0IEwxMiwzOCBMNDYsMzggTDQ2LDQgTDEyLDQgWiBNMTAsMCBMNDgsMCBDNDkuMTA0NTY5NSwtMi4wMjkwNjEyNWUtMTYgNTAsMC44OTU0MzA1IDUwLDIgTDUwLDQwIEM1MCw0MS4xMDQ1Njk1IDQ5LjEwNDU2OTUsNDIgNDgsNDIgTDEwLDQyIEM4Ljg5NTQzMDUsNDIgOCw0MS4xMDQ1Njk1IDgsNDAgTDgsMiBDOCwwLjg5NTQzMDUgOC44OTU0MzA1LDIuMDI5MDYxMjVlLTE2IDEwLDAgWiIgaWQ9IlJlY3RhbmdsZS1Db3B5Ij48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPgo="], + "link" : "https://html2canvas.hertzen.com/", + "text" : "html2canvas" +}, { + "images" : [ + "https://parall.ax/parallax-2016/img/svg/jspdf-logo.svg", + "https://camo.githubusercontent.com/54ed74d0938e90aa54fc062f91767281c46cfd9964787f1b4a7b898eca9e887e/68747470733a2f2f706172616c6c2e61782f706172616c6c61782d323031362f696d672f7376672f6a737064662d6c6f676f2e737667" + ], + "link" : "https://github.com/parallax/jsPDF", + "text" : "jsPDF" +}] ]] + +Por otro lado, hay proyectos desarrollados por KyMAN o en los que KyMAN también participó tales +como: + +[[links_group [{ + "images" : ["https://wmarkdown.k3y.pw/images/wmarkdown.png"], + "link" : "https://wmarkdown.k3y.pw/", + "text" : "WMarkDown" +}, { + "images" : [], + "link" : "https://wdictionaries.k3y.pw/", + "text" : "Wdictionaries" +}, { + "images" : [], + "link" : "https://proxycors.k3y.pw/", + "text" : "ProxyCORS" +}] ]] + +Finalmente, este proyecto es usado en los proyectos: + +[[links_group [{ + "images" : ["https://anp.k3y.pw/images/AnP.png"], + "link" : "https://anp.k3y.pw/", + "text" : "AnP" +}, { + "images" : [], + "link" : "https://anprm.k3y.pw/", + "text" : "AnPRM" +}] ]] + +[[html_data { + "title" : "JSReports - Proyectos", + "url" : "https://jsreports.k3y.pw/es/projects.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación,proyectos,dependencias", + "description" : "Proyectos y dependencias del proyecto JSReports.", + "project" : "Proyectos y dependencias", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/es/targets.w.md b/WMD/es/targets.w.md new file mode 100755 index 0000000..024a553 --- /dev/null +++ b/WMD/es/targets.w.md @@ -0,0 +1,51 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# Objetivos + +Aquí se pondrán los objetivos del proyecto JSReports. + +- [X] Crear proyecto Git. +- [X] Crear base del proyecto. +- [X] Crear el JS. +- [-] Crear la parte para HTML compacto. +- [X] Adjuntador de fuentes. +- [X] Meter todo en el CDN y comentarlo. +- [X] Añadir cabeceras y pies al PDF. +- [X] Posibilidad de múltiples cabeceras y pies. +- [X] Corregir sobreescritura de elementos CSS y el múltiple ";". +- [X] Montar el cuerpo de los DOC. +- [X] Montar cabeceras y pies de página. +- [X] Corregir Bug de tamaños de imagen. +- [X] Corregir Bug de ancho de tablas. +- [X] Corregir Bug de ancho de celdas. +- [X] Compatibilizar OpenDocument con MSDocument. +- [X] Montar variables de página. +- [X] Arreglar Bug de márgenes del Footer y el Header. +- [X] Corregir fuentes embedadas de PDF. +- /*Hasta aquí es compatible con UDF al 100%.*/ +- [ ] Montar VM temporal con el Office 365 para probar resultados y corregir Bugs. + - *Compatibilizar UDF con MS XML.* +- [-] Documentar. +- [X] Añadir JSReports al WDictionaries. +- [X] Publicar. +- [X] Montar CORS. +- [X] Subir los archivos de dependencias. +- [X] Arreglar el tester HTML. +- [X] Elimintar el tester 0 HTML. +- [X] Corregir Bug del JSReports en Chrome. + +[[html_data { + "title" : "JSReports - Objetivos", + "url" : "https://jsreports.k3y.pw/es/targets.html", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación,objetivos,targets", + "description" : "Objetivos del proyecto JSReports.", + "project" : "Objetivos", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]] diff --git a/WMD/index.w.md b/WMD/index.w.md new file mode 100755 index 0000000..6d11824 --- /dev/null +++ b/WMD/index.w.md @@ -0,0 +1,40 @@ +[[post_data { + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422 +}]] +# JSReports + +Seleccione un idioma para acceder a la documentación del proyecto. + +[[links_group [{ + "images" : ["https://i.imgur.com/im1o0gc.png"], + "link" : "/es/", + "text" : "Español", + "self" : true +}] ]] + +[[header_level 0]] +[[include /WMD/es/project.w.md]] + +[[header_level 0]] +[[include /WMD/es/projects.w.md]] + +[[header_level 0]] +[[include /WMD/es/bugs.w.md]] + +[[header_level 0]] +[[include /WMD/es/targets.w.md]] + +[[html_data { + "title" : "JSReports - Idioma", + "url" : "https://jsreports.k3y.pw/", + "author" : "KyMAN", + "since" : 20220422, + "version" : 20220422, + "key_words" : "jsreports,js,report,ecma,pdf,doc,csv,kyman,wmd,wmarkdown,documentación", + "description" : "Documentación del proyecto JSReports.", + "project" : "JSReports", + "logo" : "https://jsreports.k3y.pw/images/JSReports.png", + "language" : "es" +}]]