@files-preview-app/preview-file 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular.cjs +169 -13
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +169 -13
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +169 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +169 -13
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +169 -13
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +169 -13
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +169 -13
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +169 -13
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/angular.cjs
CHANGED
|
@@ -42,6 +42,7 @@ function _interopNamespace(e) {
|
|
|
42
42
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
43
43
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
44
44
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
45
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
45
46
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
46
47
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
47
48
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -747,9 +748,11 @@ var ToolbarController = class {
|
|
|
747
748
|
type: "button",
|
|
748
749
|
"data-action-id": id
|
|
749
750
|
});
|
|
750
|
-
const
|
|
751
|
-
if (
|
|
752
|
-
btn.innerHTML =
|
|
751
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
752
|
+
if (internalSvg) {
|
|
753
|
+
btn.innerHTML = internalSvg;
|
|
754
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
755
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
753
756
|
} else {
|
|
754
757
|
btn.textContent = title || id;
|
|
755
758
|
}
|
|
@@ -5749,8 +5752,17 @@ var DocPlugin = class {
|
|
|
5749
5752
|
let scale = 1;
|
|
5750
5753
|
let extractedRawText = "";
|
|
5751
5754
|
let isFallback = false;
|
|
5755
|
+
let chartSvg = "";
|
|
5752
5756
|
try {
|
|
5753
5757
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5758
|
+
try {
|
|
5759
|
+
const pkg = cfbf.readStream("package_stream");
|
|
5760
|
+
if (pkg && pkg.length > 100) {
|
|
5761
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
5762
|
+
}
|
|
5763
|
+
} catch (chartErr) {
|
|
5764
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
5765
|
+
}
|
|
5754
5766
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5755
5767
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5756
5768
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5768,7 +5780,7 @@ var DocPlugin = class {
|
|
|
5768
5780
|
extractedRawText = fallback;
|
|
5769
5781
|
isFallback = true;
|
|
5770
5782
|
}
|
|
5771
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
5783
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5772
5784
|
const totalPages = Math.max(1, rawPages.length);
|
|
5773
5785
|
let currentPage = 1;
|
|
5774
5786
|
const pageCards = [];
|
|
@@ -6010,7 +6022,7 @@ var DocPlugin = class {
|
|
|
6010
6022
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
6011
6023
|
const trimmed = run.trim();
|
|
6012
6024
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
6013
|
-
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
6025
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^EMBED\b/i.test(trimmed) && !trimmed.includes("ChartDocument") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
6014
6026
|
seen.add(trimmed);
|
|
6015
6027
|
candidateLines.push(trimmed);
|
|
6016
6028
|
}
|
|
@@ -6021,9 +6033,114 @@ var DocPlugin = class {
|
|
|
6021
6033
|
heuristicTextExtraction(buffer) {
|
|
6022
6034
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
6023
6035
|
}
|
|
6024
|
-
|
|
6036
|
+
/**
|
|
6037
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6038
|
+
*/
|
|
6039
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6040
|
+
try {
|
|
6041
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
6042
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6043
|
+
if (!contentXml) return "";
|
|
6044
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6045
|
+
if (rowsMatch.length < 2) return "";
|
|
6046
|
+
const headers = [];
|
|
6047
|
+
const firstRow = rowsMatch[0];
|
|
6048
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6049
|
+
for (const h of headerCells) {
|
|
6050
|
+
headers.push(h.replace(/<\/?text:p>/g, "").trim());
|
|
6051
|
+
}
|
|
6052
|
+
const categories = [];
|
|
6053
|
+
const seriesValues = headers.map(() => []);
|
|
6054
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6055
|
+
const rowStr = rowsMatch[r];
|
|
6056
|
+
if (!rowStr) continue;
|
|
6057
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6058
|
+
if (cells.length > 0 && cells[0]) {
|
|
6059
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6060
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6061
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6062
|
+
const cellStr = cells[c];
|
|
6063
|
+
if (!cellStr) continue;
|
|
6064
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6065
|
+
const series = seriesValues[c - 1];
|
|
6066
|
+
if (series) {
|
|
6067
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6073
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6074
|
+
let cIdx = 0;
|
|
6075
|
+
for (const cm of colorMatches) {
|
|
6076
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6077
|
+
cIdx++;
|
|
6078
|
+
}
|
|
6079
|
+
let maxVal = 10;
|
|
6080
|
+
for (const s of seriesValues) {
|
|
6081
|
+
for (const v of s) {
|
|
6082
|
+
if (v > maxVal) maxVal = v;
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6086
|
+
const width = 560;
|
|
6087
|
+
const height = 280;
|
|
6088
|
+
const padLeft = 45;
|
|
6089
|
+
const padRight = 100;
|
|
6090
|
+
const padTop = 20;
|
|
6091
|
+
const padBottom = 40;
|
|
6092
|
+
const chartW = width - padLeft - padRight;
|
|
6093
|
+
const chartH = height - padTop - padBottom;
|
|
6094
|
+
let svg = `<svg viewBox="0 0 ${width} ${height}" width="100%" height="auto" style="max-width: 560px; height: 280px; margin: 16px auto; display: block; font-family: Calibri, sans-serif; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 6px; box-shadow: 0 1px 4px rgba(0,0,0,0.05);">`;
|
|
6095
|
+
for (let step = 0; step <= 4; step++) {
|
|
6096
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6097
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6098
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6099
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6100
|
+
}
|
|
6101
|
+
const numCats = categories.length;
|
|
6102
|
+
const numSeries = headers.length;
|
|
6103
|
+
const groupW = chartW / numCats;
|
|
6104
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6105
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6106
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6107
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6108
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6109
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6110
|
+
const barH = val / maxVal * chartH;
|
|
6111
|
+
const barX = groupX + sIdx * barW;
|
|
6112
|
+
const barY = padTop + chartH - barH;
|
|
6113
|
+
const col = colors[sIdx % colors.length];
|
|
6114
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6115
|
+
}
|
|
6116
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6117
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6118
|
+
}
|
|
6119
|
+
let legendY = padTop + 20;
|
|
6120
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6121
|
+
const col = colors[sIdx % colors.length];
|
|
6122
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6123
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6124
|
+
legendY += 20;
|
|
6125
|
+
}
|
|
6126
|
+
svg += "</svg>";
|
|
6127
|
+
return svg;
|
|
6128
|
+
} catch (e) {
|
|
6129
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6130
|
+
return "";
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
6025
6134
|
if (!text) return "";
|
|
6026
6135
|
let cleaned = text.replace(
|
|
6136
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6137
|
+
() => chartSvg ? `
|
|
6138
|
+
|
|
6139
|
+
${chartSvg}
|
|
6140
|
+
|
|
6141
|
+
` : ""
|
|
6142
|
+
);
|
|
6143
|
+
cleaned = cleaned.replace(
|
|
6027
6144
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6028
6145
|
(_match, url, label) => {
|
|
6029
6146
|
const cleanUrl = url.trim();
|
|
@@ -6031,18 +6148,23 @@ var DocPlugin = class {
|
|
|
6031
6148
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6032
6149
|
}
|
|
6033
6150
|
);
|
|
6034
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6151
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6152
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6153
|
+
return res.trim();
|
|
6154
|
+
});
|
|
6035
6155
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6036
6156
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6157
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6158
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6037
6159
|
return cleaned;
|
|
6038
6160
|
}
|
|
6039
|
-
splitIntoPages(text) {
|
|
6161
|
+
splitIntoPages(text, chartSvg = "") {
|
|
6040
6162
|
if (!text) return [""];
|
|
6041
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6163
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6042
6164
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
6043
6165
|
const explicitParts = normalized.split(/[\x0C\f]|\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
6044
6166
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
6045
|
-
const maxLinesPerPage =
|
|
6167
|
+
const maxLinesPerPage = 34;
|
|
6046
6168
|
const charsPerLine = 80;
|
|
6047
6169
|
const finalPages = [];
|
|
6048
6170
|
for (const part of explicitParts) {
|
|
@@ -6050,8 +6172,8 @@ var DocPlugin = class {
|
|
|
6050
6172
|
let currentLines = [];
|
|
6051
6173
|
let count = 0;
|
|
6052
6174
|
for (const line of lines) {
|
|
6053
|
-
const
|
|
6054
|
-
const vLines = Math.max(1, Math.ceil((
|
|
6175
|
+
const isSvg = line.includes("<svg");
|
|
6176
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6055
6177
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6056
6178
|
finalPages.push(currentLines.join("\n"));
|
|
6057
6179
|
currentLines = [];
|
|
@@ -6091,9 +6213,44 @@ var DocPlugin = class {
|
|
|
6091
6213
|
tableLines = [];
|
|
6092
6214
|
}
|
|
6093
6215
|
};
|
|
6216
|
+
const sanitizeOptions = {
|
|
6217
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
6218
|
+
ADD_ATTR: [
|
|
6219
|
+
"href",
|
|
6220
|
+
"target",
|
|
6221
|
+
"rel",
|
|
6222
|
+
"style",
|
|
6223
|
+
"viewBox",
|
|
6224
|
+
"width",
|
|
6225
|
+
"height",
|
|
6226
|
+
"x",
|
|
6227
|
+
"y",
|
|
6228
|
+
"x1",
|
|
6229
|
+
"y1",
|
|
6230
|
+
"x2",
|
|
6231
|
+
"y2",
|
|
6232
|
+
"fill",
|
|
6233
|
+
"stroke",
|
|
6234
|
+
"stroke-width",
|
|
6235
|
+
"stroke-dasharray",
|
|
6236
|
+
"rx",
|
|
6237
|
+
"font-size",
|
|
6238
|
+
"text-anchor"
|
|
6239
|
+
]
|
|
6240
|
+
};
|
|
6094
6241
|
let i = 0;
|
|
6095
6242
|
while (i < lines.length) {
|
|
6096
6243
|
let line = lines[i];
|
|
6244
|
+
if (line.includes("<svg")) {
|
|
6245
|
+
if (inList) {
|
|
6246
|
+
html += "</ul>";
|
|
6247
|
+
inList = false;
|
|
6248
|
+
}
|
|
6249
|
+
flushTable();
|
|
6250
|
+
html += line;
|
|
6251
|
+
i++;
|
|
6252
|
+
continue;
|
|
6253
|
+
}
|
|
6097
6254
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6098
6255
|
if (tabCount > 0) {
|
|
6099
6256
|
let j = i;
|
|
@@ -6127,7 +6284,6 @@ var DocPlugin = class {
|
|
|
6127
6284
|
i++;
|
|
6128
6285
|
continue;
|
|
6129
6286
|
}
|
|
6130
|
-
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
6131
6287
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
6132
6288
|
if (inList) {
|
|
6133
6289
|
html += "</ul>";
|