@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/vue.cjs
CHANGED
|
@@ -41,6 +41,7 @@ function _interopNamespace(e) {
|
|
|
41
41
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
42
42
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
43
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
44
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
44
45
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
45
46
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
46
47
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -699,9 +700,11 @@ var ToolbarController = class {
|
|
|
699
700
|
type: "button",
|
|
700
701
|
"data-action-id": id
|
|
701
702
|
});
|
|
702
|
-
const
|
|
703
|
-
if (
|
|
704
|
-
btn.innerHTML =
|
|
703
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
704
|
+
if (internalSvg) {
|
|
705
|
+
btn.innerHTML = internalSvg;
|
|
706
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
707
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
705
708
|
} else {
|
|
706
709
|
btn.textContent = title || id;
|
|
707
710
|
}
|
|
@@ -5701,8 +5704,17 @@ var DocPlugin = class {
|
|
|
5701
5704
|
let scale = 1;
|
|
5702
5705
|
let extractedRawText = "";
|
|
5703
5706
|
let isFallback = false;
|
|
5707
|
+
let chartSvg = "";
|
|
5704
5708
|
try {
|
|
5705
5709
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5710
|
+
try {
|
|
5711
|
+
const pkg = cfbf.readStream("package_stream");
|
|
5712
|
+
if (pkg && pkg.length > 100) {
|
|
5713
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
5714
|
+
}
|
|
5715
|
+
} catch (chartErr) {
|
|
5716
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
5717
|
+
}
|
|
5706
5718
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5707
5719
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5708
5720
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5720,7 +5732,7 @@ var DocPlugin = class {
|
|
|
5720
5732
|
extractedRawText = fallback;
|
|
5721
5733
|
isFallback = true;
|
|
5722
5734
|
}
|
|
5723
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
5735
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5724
5736
|
const totalPages = Math.max(1, rawPages.length);
|
|
5725
5737
|
let currentPage = 1;
|
|
5726
5738
|
const pageCards = [];
|
|
@@ -5962,7 +5974,7 @@ var DocPlugin = class {
|
|
|
5962
5974
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
5963
5975
|
const trimmed = run.trim();
|
|
5964
5976
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
5965
|
-
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)) {
|
|
5977
|
+
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)) {
|
|
5966
5978
|
seen.add(trimmed);
|
|
5967
5979
|
candidateLines.push(trimmed);
|
|
5968
5980
|
}
|
|
@@ -5973,9 +5985,114 @@ var DocPlugin = class {
|
|
|
5973
5985
|
heuristicTextExtraction(buffer) {
|
|
5974
5986
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
5975
5987
|
}
|
|
5976
|
-
|
|
5988
|
+
/**
|
|
5989
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
5990
|
+
*/
|
|
5991
|
+
parseOdfChartToSvg(zipBytes) {
|
|
5992
|
+
try {
|
|
5993
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
5994
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
5995
|
+
if (!contentXml) return "";
|
|
5996
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
5997
|
+
if (rowsMatch.length < 2) return "";
|
|
5998
|
+
const headers = [];
|
|
5999
|
+
const firstRow = rowsMatch[0];
|
|
6000
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6001
|
+
for (const h2 of headerCells) {
|
|
6002
|
+
headers.push(h2.replace(/<\/?text:p>/g, "").trim());
|
|
6003
|
+
}
|
|
6004
|
+
const categories = [];
|
|
6005
|
+
const seriesValues = headers.map(() => []);
|
|
6006
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6007
|
+
const rowStr = rowsMatch[r];
|
|
6008
|
+
if (!rowStr) continue;
|
|
6009
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6010
|
+
if (cells.length > 0 && cells[0]) {
|
|
6011
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6012
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6013
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6014
|
+
const cellStr = cells[c];
|
|
6015
|
+
if (!cellStr) continue;
|
|
6016
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6017
|
+
const series = seriesValues[c - 1];
|
|
6018
|
+
if (series) {
|
|
6019
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6025
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6026
|
+
let cIdx = 0;
|
|
6027
|
+
for (const cm of colorMatches) {
|
|
6028
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6029
|
+
cIdx++;
|
|
6030
|
+
}
|
|
6031
|
+
let maxVal = 10;
|
|
6032
|
+
for (const s of seriesValues) {
|
|
6033
|
+
for (const v of s) {
|
|
6034
|
+
if (v > maxVal) maxVal = v;
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6038
|
+
const width = 560;
|
|
6039
|
+
const height = 280;
|
|
6040
|
+
const padLeft = 45;
|
|
6041
|
+
const padRight = 100;
|
|
6042
|
+
const padTop = 20;
|
|
6043
|
+
const padBottom = 40;
|
|
6044
|
+
const chartW = width - padLeft - padRight;
|
|
6045
|
+
const chartH = height - padTop - padBottom;
|
|
6046
|
+
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);">`;
|
|
6047
|
+
for (let step = 0; step <= 4; step++) {
|
|
6048
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6049
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6050
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6051
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6052
|
+
}
|
|
6053
|
+
const numCats = categories.length;
|
|
6054
|
+
const numSeries = headers.length;
|
|
6055
|
+
const groupW = chartW / numCats;
|
|
6056
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6057
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6058
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6059
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6060
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6061
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6062
|
+
const barH = val / maxVal * chartH;
|
|
6063
|
+
const barX = groupX + sIdx * barW;
|
|
6064
|
+
const barY = padTop + chartH - barH;
|
|
6065
|
+
const col = colors[sIdx % colors.length];
|
|
6066
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6067
|
+
}
|
|
6068
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6069
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6070
|
+
}
|
|
6071
|
+
let legendY = padTop + 20;
|
|
6072
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6073
|
+
const col = colors[sIdx % colors.length];
|
|
6074
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6075
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6076
|
+
legendY += 20;
|
|
6077
|
+
}
|
|
6078
|
+
svg += "</svg>";
|
|
6079
|
+
return svg;
|
|
6080
|
+
} catch (e) {
|
|
6081
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6082
|
+
return "";
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
5977
6086
|
if (!text) return "";
|
|
5978
6087
|
let cleaned = text.replace(
|
|
6088
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6089
|
+
() => chartSvg ? `
|
|
6090
|
+
|
|
6091
|
+
${chartSvg}
|
|
6092
|
+
|
|
6093
|
+
` : ""
|
|
6094
|
+
);
|
|
6095
|
+
cleaned = cleaned.replace(
|
|
5979
6096
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
5980
6097
|
(_match, url, label) => {
|
|
5981
6098
|
const cleanUrl = url.trim();
|
|
@@ -5983,18 +6100,23 @@ var DocPlugin = class {
|
|
|
5983
6100
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
5984
6101
|
}
|
|
5985
6102
|
);
|
|
5986
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6103
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6104
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6105
|
+
return res.trim();
|
|
6106
|
+
});
|
|
5987
6107
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
5988
6108
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6109
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6110
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
5989
6111
|
return cleaned;
|
|
5990
6112
|
}
|
|
5991
|
-
splitIntoPages(text) {
|
|
6113
|
+
splitIntoPages(text, chartSvg = "") {
|
|
5992
6114
|
if (!text) return [""];
|
|
5993
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6115
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
5994
6116
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
5995
6117
|
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);
|
|
5996
6118
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
5997
|
-
const maxLinesPerPage =
|
|
6119
|
+
const maxLinesPerPage = 34;
|
|
5998
6120
|
const charsPerLine = 80;
|
|
5999
6121
|
const finalPages = [];
|
|
6000
6122
|
for (const part of explicitParts) {
|
|
@@ -6002,8 +6124,8 @@ var DocPlugin = class {
|
|
|
6002
6124
|
let currentLines = [];
|
|
6003
6125
|
let count = 0;
|
|
6004
6126
|
for (const line of lines) {
|
|
6005
|
-
const
|
|
6006
|
-
const vLines = Math.max(1, Math.ceil((
|
|
6127
|
+
const isSvg = line.includes("<svg");
|
|
6128
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6007
6129
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6008
6130
|
finalPages.push(currentLines.join("\n"));
|
|
6009
6131
|
currentLines = [];
|
|
@@ -6043,9 +6165,44 @@ var DocPlugin = class {
|
|
|
6043
6165
|
tableLines = [];
|
|
6044
6166
|
}
|
|
6045
6167
|
};
|
|
6168
|
+
const sanitizeOptions = {
|
|
6169
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
6170
|
+
ADD_ATTR: [
|
|
6171
|
+
"href",
|
|
6172
|
+
"target",
|
|
6173
|
+
"rel",
|
|
6174
|
+
"style",
|
|
6175
|
+
"viewBox",
|
|
6176
|
+
"width",
|
|
6177
|
+
"height",
|
|
6178
|
+
"x",
|
|
6179
|
+
"y",
|
|
6180
|
+
"x1",
|
|
6181
|
+
"y1",
|
|
6182
|
+
"x2",
|
|
6183
|
+
"y2",
|
|
6184
|
+
"fill",
|
|
6185
|
+
"stroke",
|
|
6186
|
+
"stroke-width",
|
|
6187
|
+
"stroke-dasharray",
|
|
6188
|
+
"rx",
|
|
6189
|
+
"font-size",
|
|
6190
|
+
"text-anchor"
|
|
6191
|
+
]
|
|
6192
|
+
};
|
|
6046
6193
|
let i = 0;
|
|
6047
6194
|
while (i < lines.length) {
|
|
6048
6195
|
let line = lines[i];
|
|
6196
|
+
if (line.includes("<svg")) {
|
|
6197
|
+
if (inList) {
|
|
6198
|
+
html += "</ul>";
|
|
6199
|
+
inList = false;
|
|
6200
|
+
}
|
|
6201
|
+
flushTable();
|
|
6202
|
+
html += line;
|
|
6203
|
+
i++;
|
|
6204
|
+
continue;
|
|
6205
|
+
}
|
|
6049
6206
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6050
6207
|
if (tabCount > 0) {
|
|
6051
6208
|
let j = i;
|
|
@@ -6079,7 +6236,6 @@ var DocPlugin = class {
|
|
|
6079
6236
|
i++;
|
|
6080
6237
|
continue;
|
|
6081
6238
|
}
|
|
6082
|
-
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
6083
6239
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
6084
6240
|
if (inList) {
|
|
6085
6241
|
html += "</ul>";
|