@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/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ function _interopNamespace(e) {
|
|
|
38
38
|
var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
|
|
39
39
|
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
40
40
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
41
|
+
var fflate__namespace = /*#__PURE__*/_interopNamespace(fflate);
|
|
41
42
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
42
43
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
43
44
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
@@ -781,9 +782,11 @@ var ToolbarController = class {
|
|
|
781
782
|
type: "button",
|
|
782
783
|
"data-action-id": id
|
|
783
784
|
});
|
|
784
|
-
const
|
|
785
|
-
if (
|
|
786
|
-
btn.innerHTML =
|
|
785
|
+
const internalSvg = ICON_MAP[iconHtml] || ICON_MAP[id];
|
|
786
|
+
if (internalSvg) {
|
|
787
|
+
btn.innerHTML = internalSvg;
|
|
788
|
+
} else if (iconHtml && iconHtml.startsWith("<svg")) {
|
|
789
|
+
btn.innerHTML = sanitizeSVG(iconHtml);
|
|
787
790
|
} else {
|
|
788
791
|
btn.textContent = title || id;
|
|
789
792
|
}
|
|
@@ -5783,8 +5786,17 @@ var DocPlugin = class {
|
|
|
5783
5786
|
let scale = 1;
|
|
5784
5787
|
let extractedRawText = "";
|
|
5785
5788
|
let isFallback = false;
|
|
5789
|
+
let chartSvg = "";
|
|
5786
5790
|
try {
|
|
5787
5791
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
5792
|
+
try {
|
|
5793
|
+
const pkg = cfbf.readStream("package_stream");
|
|
5794
|
+
if (pkg && pkg.length > 100) {
|
|
5795
|
+
chartSvg = this.parseOdfChartToSvg(pkg);
|
|
5796
|
+
}
|
|
5797
|
+
} catch (chartErr) {
|
|
5798
|
+
console.warn("[DocPlugin] Chart stream parsing info:", chartErr);
|
|
5799
|
+
}
|
|
5788
5800
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
5789
5801
|
if (!wordDocStream || wordDocStream.length < 512) {
|
|
5790
5802
|
throw new Error("WordDocument stream not found or invalid in CFBF archive");
|
|
@@ -5802,7 +5814,7 @@ var DocPlugin = class {
|
|
|
5802
5814
|
extractedRawText = fallback;
|
|
5803
5815
|
isFallback = true;
|
|
5804
5816
|
}
|
|
5805
|
-
const rawPages = this.splitIntoPages(extractedRawText);
|
|
5817
|
+
const rawPages = this.splitIntoPages(extractedRawText, chartSvg);
|
|
5806
5818
|
const totalPages = Math.max(1, rawPages.length);
|
|
5807
5819
|
let currentPage = 1;
|
|
5808
5820
|
const pageCards = [];
|
|
@@ -6044,7 +6056,7 @@ var DocPlugin = class {
|
|
|
6044
6056
|
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
6045
6057
|
const trimmed = run.trim();
|
|
6046
6058
|
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
6047
|
-
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)) {
|
|
6059
|
+
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)) {
|
|
6048
6060
|
seen.add(trimmed);
|
|
6049
6061
|
candidateLines.push(trimmed);
|
|
6050
6062
|
}
|
|
@@ -6055,9 +6067,114 @@ var DocPlugin = class {
|
|
|
6055
6067
|
heuristicTextExtraction(buffer) {
|
|
6056
6068
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
6057
6069
|
}
|
|
6058
|
-
|
|
6070
|
+
/**
|
|
6071
|
+
* Parses an embedded OpenDocument Chart package into a vector SVG bar/column chart
|
|
6072
|
+
*/
|
|
6073
|
+
parseOdfChartToSvg(zipBytes) {
|
|
6074
|
+
try {
|
|
6075
|
+
const unzipped = fflate__namespace.unzipSync(zipBytes);
|
|
6076
|
+
const contentXml = unzipped["content.xml"] ? new TextDecoder("utf-8").decode(unzipped["content.xml"]) : "";
|
|
6077
|
+
if (!contentXml) return "";
|
|
6078
|
+
const rowsMatch = contentXml.match(/<table:table-row[\s\S]*?<\/table:table-row>/g) || [];
|
|
6079
|
+
if (rowsMatch.length < 2) return "";
|
|
6080
|
+
const headers = [];
|
|
6081
|
+
const firstRow = rowsMatch[0];
|
|
6082
|
+
const headerCells = firstRow ? firstRow.match(/<text:p>([^<]+)<\/text:p>/g) || [] : [];
|
|
6083
|
+
for (const h of headerCells) {
|
|
6084
|
+
headers.push(h.replace(/<\/?text:p>/g, "").trim());
|
|
6085
|
+
}
|
|
6086
|
+
const categories = [];
|
|
6087
|
+
const seriesValues = headers.map(() => []);
|
|
6088
|
+
for (let r = 1; r < rowsMatch.length; r++) {
|
|
6089
|
+
const rowStr = rowsMatch[r];
|
|
6090
|
+
if (!rowStr) continue;
|
|
6091
|
+
const cells = rowStr.match(/<table:table-cell[\s\S]*?<\/table:table-cell>/g) || [];
|
|
6092
|
+
if (cells.length > 0 && cells[0]) {
|
|
6093
|
+
const catMatch = cells[0].match(/<text:p>([^<]+)<\/text:p>/);
|
|
6094
|
+
categories.push(catMatch ? catMatch[1] : "Row " + r);
|
|
6095
|
+
for (let c = 1; c < cells.length && c - 1 < headers.length; c++) {
|
|
6096
|
+
const cellStr = cells[c];
|
|
6097
|
+
if (!cellStr) continue;
|
|
6098
|
+
const valMatch = cellStr.match(/office:value="([0-9.]+)"/) || cellStr.match(/<text:p>([0-9.]+)<\/text:p>/);
|
|
6099
|
+
const series = seriesValues[c - 1];
|
|
6100
|
+
if (series) {
|
|
6101
|
+
series.push(valMatch ? parseFloat(valMatch[1]) : 0);
|
|
6102
|
+
}
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
}
|
|
6106
|
+
const colors = ["#004586", "#ff420e", "#ffd320", "#579d1c", "#7e0021"];
|
|
6107
|
+
const colorMatches = contentXml.matchAll(/draw:fill-color="(#[0-9a-fA-F]{6})"/g);
|
|
6108
|
+
let cIdx = 0;
|
|
6109
|
+
for (const cm of colorMatches) {
|
|
6110
|
+
if (cIdx < colors.length) colors[cIdx] = cm[1];
|
|
6111
|
+
cIdx++;
|
|
6112
|
+
}
|
|
6113
|
+
let maxVal = 10;
|
|
6114
|
+
for (const s of seriesValues) {
|
|
6115
|
+
for (const v of s) {
|
|
6116
|
+
if (v > maxVal) maxVal = v;
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6119
|
+
maxVal = Math.ceil(maxVal * 1.15);
|
|
6120
|
+
const width = 560;
|
|
6121
|
+
const height = 280;
|
|
6122
|
+
const padLeft = 45;
|
|
6123
|
+
const padRight = 100;
|
|
6124
|
+
const padTop = 20;
|
|
6125
|
+
const padBottom = 40;
|
|
6126
|
+
const chartW = width - padLeft - padRight;
|
|
6127
|
+
const chartH = height - padTop - padBottom;
|
|
6128
|
+
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);">`;
|
|
6129
|
+
for (let step = 0; step <= 4; step++) {
|
|
6130
|
+
const yVal = (maxVal / 4 * step).toFixed(1);
|
|
6131
|
+
const yPos = padTop + chartH - step / 4 * chartH;
|
|
6132
|
+
svg += `<line x1="${padLeft}" y1="${yPos}" x2="${padLeft + chartW}" y2="${yPos}" stroke="#e2e8f0" stroke-dasharray="2,2" />`;
|
|
6133
|
+
svg += `<text x="${padLeft - 8}" y="${yPos + 4}" font-size="11" fill="#64748b" text-anchor="end">${yVal}</text>`;
|
|
6134
|
+
}
|
|
6135
|
+
const numCats = categories.length;
|
|
6136
|
+
const numSeries = headers.length;
|
|
6137
|
+
const groupW = chartW / numCats;
|
|
6138
|
+
const barW = Math.max(8, groupW * 0.7 / numSeries);
|
|
6139
|
+
const groupPad = (groupW - barW * numSeries) / 2;
|
|
6140
|
+
for (let catIdx = 0; catIdx < numCats; catIdx++) {
|
|
6141
|
+
const groupX = padLeft + catIdx * groupW + groupPad;
|
|
6142
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6143
|
+
const val = seriesValues[sIdx][catIdx] || 0;
|
|
6144
|
+
const barH = val / maxVal * chartH;
|
|
6145
|
+
const barX = groupX + sIdx * barW;
|
|
6146
|
+
const barY = padTop + chartH - barH;
|
|
6147
|
+
const col = colors[sIdx % colors.length];
|
|
6148
|
+
svg += `<rect x="${barX}" y="${barY}" width="${barW - 2}" height="${barH}" fill="${col}" rx="2"><title>${headers[sIdx]}: ${val}</title></rect>`;
|
|
6149
|
+
}
|
|
6150
|
+
const catX = padLeft + catIdx * groupW + groupW / 2;
|
|
6151
|
+
svg += `<text x="${catX}" y="${padTop + chartH + 18}" font-size="11" fill="#475569" text-anchor="middle">${categories[catIdx]}</text>`;
|
|
6152
|
+
}
|
|
6153
|
+
let legendY = padTop + 20;
|
|
6154
|
+
for (let sIdx = 0; sIdx < numSeries; sIdx++) {
|
|
6155
|
+
const col = colors[sIdx % colors.length];
|
|
6156
|
+
svg += `<rect x="${padLeft + chartW + 15}" y="${legendY}" width="12" height="12" fill="${col}" rx="2" />`;
|
|
6157
|
+
svg += `<text x="${padLeft + chartW + 32}" y="${legendY + 10}" font-size="11" fill="#334155">${headers[sIdx]}</text>`;
|
|
6158
|
+
legendY += 20;
|
|
6159
|
+
}
|
|
6160
|
+
svg += "</svg>";
|
|
6161
|
+
return svg;
|
|
6162
|
+
} catch (e) {
|
|
6163
|
+
console.warn("[DocPlugin] Error generating chart SVG:", e);
|
|
6164
|
+
return "";
|
|
6165
|
+
}
|
|
6166
|
+
}
|
|
6167
|
+
cleanWordDocFields(text, chartSvg = "") {
|
|
6059
6168
|
if (!text) return "";
|
|
6060
6169
|
let cleaned = text.replace(
|
|
6170
|
+
/\x13\s*EMBED\b[\s\S]*?\x15/gi,
|
|
6171
|
+
() => chartSvg ? `
|
|
6172
|
+
|
|
6173
|
+
${chartSvg}
|
|
6174
|
+
|
|
6175
|
+
` : ""
|
|
6176
|
+
);
|
|
6177
|
+
cleaned = cleaned.replace(
|
|
6061
6178
|
/\x13\s*HYPERLINK\s*"?([^"\x14]+)"?\s*\x14([\s\S]*?)\x15/gi,
|
|
6062
6179
|
(_match, url, label) => {
|
|
6063
6180
|
const cleanUrl = url.trim();
|
|
@@ -6065,18 +6182,23 @@ var DocPlugin = class {
|
|
|
6065
6182
|
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer" style="color: #2563eb; text-decoration: underline;">${cleanLabel}</a>`;
|
|
6066
6183
|
}
|
|
6067
6184
|
);
|
|
6068
|
-
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g,
|
|
6185
|
+
cleaned = cleaned.replace(/\x13[^\x14\x15]*\x14([^\x15]*)\x15/g, (_m, res) => {
|
|
6186
|
+
if (/[\x00-\x1F]/.test(res)) return "";
|
|
6187
|
+
return res.trim();
|
|
6188
|
+
});
|
|
6069
6189
|
cleaned = cleaned.replace(/\x13[^\x15]*\x15/g, "");
|
|
6070
6190
|
cleaned = cleaned.replace(/[\x13\x14\x15]/g, "");
|
|
6191
|
+
cleaned = cleaned.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
6192
|
+
cleaned = cleaned.replace(/EMBED\s+LibreOffice\.ChartDocument\.[0-9]+/gi, chartSvg || "");
|
|
6071
6193
|
return cleaned;
|
|
6072
6194
|
}
|
|
6073
|
-
splitIntoPages(text) {
|
|
6195
|
+
splitIntoPages(text, chartSvg = "") {
|
|
6074
6196
|
if (!text) return [""];
|
|
6075
|
-
const cleanedText = this.cleanWordDocFields(text);
|
|
6197
|
+
const cleanedText = this.cleanWordDocFields(text, chartSvg);
|
|
6076
6198
|
const normalized = cleanedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").replace(/\x07\n/g, "\n").replace(/\x07/g, " ");
|
|
6077
6199
|
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);
|
|
6078
6200
|
if (explicitParts.length === 0) explicitParts.push(normalized);
|
|
6079
|
-
const maxLinesPerPage =
|
|
6201
|
+
const maxLinesPerPage = 34;
|
|
6080
6202
|
const charsPerLine = 80;
|
|
6081
6203
|
const finalPages = [];
|
|
6082
6204
|
for (const part of explicitParts) {
|
|
@@ -6084,8 +6206,8 @@ var DocPlugin = class {
|
|
|
6084
6206
|
let currentLines = [];
|
|
6085
6207
|
let count = 0;
|
|
6086
6208
|
for (const line of lines) {
|
|
6087
|
-
const
|
|
6088
|
-
const vLines = Math.max(1, Math.ceil((
|
|
6209
|
+
const isSvg = line.includes("<svg");
|
|
6210
|
+
const vLines = isSvg ? 12 : Math.max(1, Math.ceil((line.replace(/<[^>]+>/g, "").length || 1) / charsPerLine));
|
|
6089
6211
|
if (count + vLines > maxLinesPerPage && currentLines.length > 0) {
|
|
6090
6212
|
finalPages.push(currentLines.join("\n"));
|
|
6091
6213
|
currentLines = [];
|
|
@@ -6125,9 +6247,44 @@ var DocPlugin = class {
|
|
|
6125
6247
|
tableLines = [];
|
|
6126
6248
|
}
|
|
6127
6249
|
};
|
|
6250
|
+
const sanitizeOptions = {
|
|
6251
|
+
ADD_TAGS: ["a", "svg", "g", "path", "line", "rect", "circle", "text", "title"],
|
|
6252
|
+
ADD_ATTR: [
|
|
6253
|
+
"href",
|
|
6254
|
+
"target",
|
|
6255
|
+
"rel",
|
|
6256
|
+
"style",
|
|
6257
|
+
"viewBox",
|
|
6258
|
+
"width",
|
|
6259
|
+
"height",
|
|
6260
|
+
"x",
|
|
6261
|
+
"y",
|
|
6262
|
+
"x1",
|
|
6263
|
+
"y1",
|
|
6264
|
+
"x2",
|
|
6265
|
+
"y2",
|
|
6266
|
+
"fill",
|
|
6267
|
+
"stroke",
|
|
6268
|
+
"stroke-width",
|
|
6269
|
+
"stroke-dasharray",
|
|
6270
|
+
"rx",
|
|
6271
|
+
"font-size",
|
|
6272
|
+
"text-anchor"
|
|
6273
|
+
]
|
|
6274
|
+
};
|
|
6128
6275
|
let i = 0;
|
|
6129
6276
|
while (i < lines.length) {
|
|
6130
6277
|
let line = lines[i];
|
|
6278
|
+
if (line.includes("<svg")) {
|
|
6279
|
+
if (inList) {
|
|
6280
|
+
html += "</ul>";
|
|
6281
|
+
inList = false;
|
|
6282
|
+
}
|
|
6283
|
+
flushTable();
|
|
6284
|
+
html += line;
|
|
6285
|
+
i++;
|
|
6286
|
+
continue;
|
|
6287
|
+
}
|
|
6131
6288
|
let tabCount = (line.match(/\t/g) || []).length;
|
|
6132
6289
|
if (tabCount > 0) {
|
|
6133
6290
|
let j = i;
|
|
@@ -6161,7 +6318,6 @@ var DocPlugin = class {
|
|
|
6161
6318
|
i++;
|
|
6162
6319
|
continue;
|
|
6163
6320
|
}
|
|
6164
|
-
const sanitizeOptions = { ADD_TAGS: ["a"], ADD_ATTR: ["href", "target", "rel", "style"] };
|
|
6165
6321
|
if (line.length < 60 && !line.endsWith(".") && (/^[A-Z0-9\s:_-]+$/.test(line) || line.startsWith("#"))) {
|
|
6166
6322
|
if (inList) {
|
|
6167
6323
|
html += "</ul>";
|