@file-viewer/renderer-text 2.2.8 → 2.3.0
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/code.js +5 -5
- package/dist/largeText.js +96 -26
- package/dist/markdown.js +37 -5
- package/dist/patch.d.ts +1 -1
- package/dist/patch.js +4 -3
- package/package.json +5 -4
package/dist/code.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter,
|
|
1
|
+
import { createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, decodeFileViewerTextBuffer, registerFileViewerZoomProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
|
|
2
2
|
import { codeStyle } from './codeStyle.js';
|
|
3
3
|
import renderLargeText, { shouldVirtualizeTextBuffer } from './largeText.js';
|
|
4
4
|
const languageMap = {
|
|
@@ -149,7 +149,7 @@ const createLineNumberText = (lineCount) => {
|
|
|
149
149
|
* @param type 文件扩展名,用于选择 highlight.js 语言
|
|
150
150
|
*/
|
|
151
151
|
export default async function renderText(buffer, target, type, context) {
|
|
152
|
-
var _a, _b, _c, _d;
|
|
152
|
+
var _a, _b, _c, _d, _e, _f;
|
|
153
153
|
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
154
154
|
const extension = type || 'txt';
|
|
155
155
|
const normalizedExtension = extension.trim().toLowerCase();
|
|
@@ -166,11 +166,11 @@ export default async function renderText(buffer, target, type, context) {
|
|
|
166
166
|
const { default: renderGitBundle } = await import('./gitBundle.js');
|
|
167
167
|
return renderGitBundle(buffer, target, extension, context);
|
|
168
168
|
}
|
|
169
|
-
const text =
|
|
169
|
+
const text = decodeFileViewerTextBuffer(buffer, (_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.encoding).text;
|
|
170
170
|
const language = resolveLanguage(extension);
|
|
171
171
|
const lineCount = lineCountOf(text);
|
|
172
|
-
const showToolbar = ((
|
|
173
|
-
const showLineNumbers = ((
|
|
172
|
+
const showToolbar = ((_d = (_c = context === null || context === void 0 ? void 0 : context.options) === null || _c === void 0 ? void 0 : _c.text) === null || _d === void 0 ? void 0 : _d.toolbar) !== false;
|
|
173
|
+
const showLineNumbers = ((_f = (_e = context === null || context === void 0 ? void 0 : context.options) === null || _e === void 0 ? void 0 : _e.text) === null || _f === void 0 ? void 0 : _f.lineNumbers) === true;
|
|
174
174
|
let disposed = false;
|
|
175
175
|
let zoom = 1;
|
|
176
176
|
const zoomEmitter = createZoomChangeEmitter();
|
package/dist/largeText.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_FILE_VIEWER_SEARCH_MAX_MATCHES, createEmptyFileViewerSearchState, createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, normalizeFileViewerSearchOptions, registerFileViewerSearchProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
|
|
1
|
+
import { DEFAULT_FILE_VIEWER_SEARCH_MAX_MATCHES, createFileViewerTextDecoder, createEmptyFileViewerSearchState, createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, normalizeFileViewerSearchOptions, resolveFileViewerTextEncoding, registerFileViewerSearchProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
|
|
2
2
|
import { codeStyle } from './codeStyle.js';
|
|
3
3
|
export const DEFAULT_LARGE_TEXT_THRESHOLD_BYTES = 512 * 1024;
|
|
4
4
|
export const DEFAULT_LARGE_TEXT_LINE_SEGMENT_BYTES = 16 * 1024;
|
|
@@ -42,6 +42,42 @@ const alignUtf8End = (bytes, offset, limit) => {
|
|
|
42
42
|
}
|
|
43
43
|
return nextOffset;
|
|
44
44
|
};
|
|
45
|
+
const gb18030UnitLength = (bytes, offset, limit) => {
|
|
46
|
+
const first = bytes[offset];
|
|
47
|
+
const second = bytes[offset + 1];
|
|
48
|
+
const third = bytes[offset + 2];
|
|
49
|
+
const fourth = bytes[offset + 3];
|
|
50
|
+
if (first === undefined || first <= 0x7f) {
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
if (first >= 0x81 && first <= 0xfe) {
|
|
54
|
+
if (second !== undefined && second >= 0x30 && second <= 0x39 &&
|
|
55
|
+
third !== undefined && third >= 0x81 && third <= 0xfe &&
|
|
56
|
+
fourth !== undefined && fourth >= 0x30 && fourth <= 0x39 &&
|
|
57
|
+
offset + 4 <= limit) {
|
|
58
|
+
return 4;
|
|
59
|
+
}
|
|
60
|
+
if (second !== undefined &&
|
|
61
|
+
((second >= 0x40 && second <= 0x7e) || (second >= 0x80 && second <= 0xfe)) &&
|
|
62
|
+
offset + 2 <= limit) {
|
|
63
|
+
return 2;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return 1;
|
|
67
|
+
};
|
|
68
|
+
const alignGb18030Boundary = (bytes, knownBoundary, requestedOffset, limit) => {
|
|
69
|
+
let cursor = clamp(knownBoundary, 0, limit);
|
|
70
|
+
const requested = clamp(requestedOffset, cursor, limit);
|
|
71
|
+
while (cursor < requested) {
|
|
72
|
+
cursor = Math.min(limit, cursor + gb18030UnitLength(bytes, cursor, limit));
|
|
73
|
+
}
|
|
74
|
+
return cursor;
|
|
75
|
+
};
|
|
76
|
+
const alignTextBoundary = (index, knownBoundary, requestedOffset, limit) => {
|
|
77
|
+
return index.encoding === 'gb18030'
|
|
78
|
+
? alignGb18030Boundary(index.bytes, knownBoundary, requestedOffset, limit)
|
|
79
|
+
: alignUtf8End(index.bytes, requestedOffset, limit);
|
|
80
|
+
};
|
|
45
81
|
const isLineBreak = (bytes, offset) => {
|
|
46
82
|
const byte = bytes[offset];
|
|
47
83
|
if (byte === 13) {
|
|
@@ -49,7 +85,7 @@ const isLineBreak = (bytes, offset) => {
|
|
|
49
85
|
}
|
|
50
86
|
return byte === 10 ? 1 : 0;
|
|
51
87
|
};
|
|
52
|
-
const buildLargeTextIndex = async (bytes, target, onProgress) => {
|
|
88
|
+
const buildLargeTextIndex = async (bytes, encoding, target, onProgress) => {
|
|
53
89
|
const checkpoints = [0];
|
|
54
90
|
let lineIndex = 0;
|
|
55
91
|
let offset = 0;
|
|
@@ -76,6 +112,7 @@ const buildLargeTextIndex = async (bytes, target, onProgress) => {
|
|
|
76
112
|
return {
|
|
77
113
|
bytes,
|
|
78
114
|
checkpoints,
|
|
115
|
+
encoding,
|
|
79
116
|
lineCount: lineIndex + 1
|
|
80
117
|
};
|
|
81
118
|
};
|
|
@@ -140,10 +177,12 @@ const decodeLargeTextSegment = (index, line, segmentIndex, segmentBytes) => {
|
|
|
140
177
|
const normalizedSegment = clamp(Math.trunc(segmentIndex), 0, segmentCount - 1);
|
|
141
178
|
const rawStart = line.start + (normalizedSegment * segmentBytes);
|
|
142
179
|
const rawEnd = Math.min(line.end, rawStart + segmentBytes);
|
|
143
|
-
const start =
|
|
144
|
-
|
|
180
|
+
const start = index.encoding === 'gb18030'
|
|
181
|
+
? alignTextBoundary(index, line.start, rawStart, line.end)
|
|
182
|
+
: alignUtf8Start(index.bytes, rawStart, line.end);
|
|
183
|
+
const end = alignTextBoundary(index, start, rawEnd, line.end);
|
|
145
184
|
return {
|
|
146
|
-
text:
|
|
185
|
+
text: createFileViewerTextDecoder(index.encoding).decode(index.bytes.subarray(start, end)),
|
|
147
186
|
segmentCount,
|
|
148
187
|
segmentIndex: normalizedSegment
|
|
149
188
|
};
|
|
@@ -167,20 +206,30 @@ const cloneLargeTextSearchState = (state) => ({
|
|
|
167
206
|
matches: state.matches.map(match => ({ ...match }))
|
|
168
207
|
});
|
|
169
208
|
export const shouldVirtualizeTextBuffer = (buffer, context) => {
|
|
170
|
-
var _a, _b;
|
|
209
|
+
var _a, _b, _c, _d;
|
|
171
210
|
const configured = (_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.virtualizeAboveBytes;
|
|
172
211
|
const threshold = Number.isFinite(configured)
|
|
173
212
|
? Math.max(0, Number(configured))
|
|
174
213
|
: DEFAULT_LARGE_TEXT_THRESHOLD_BYTES;
|
|
175
|
-
|
|
214
|
+
if (buffer.byteLength <= threshold) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
const bytes = new Uint8Array(buffer);
|
|
218
|
+
const { encoding } = resolveFileViewerTextEncoding(bytes, (_d = (_c = context === null || context === void 0 ? void 0 : context.options) === null || _c === void 0 ? void 0 : _c.text) === null || _d === void 0 ? void 0 : _d.encoding);
|
|
219
|
+
return encoding !== 'utf-16le' && encoding !== 'utf-16be';
|
|
176
220
|
};
|
|
177
221
|
export const shouldVirtualizeMarkdownBuffer = (buffer, context) => {
|
|
178
|
-
var _a, _b;
|
|
222
|
+
var _a, _b, _c, _d;
|
|
179
223
|
const configured = (_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.markdownVirtualizeAboveBytes;
|
|
180
224
|
if (!Number.isFinite(configured)) {
|
|
181
225
|
return false;
|
|
182
226
|
}
|
|
183
|
-
|
|
227
|
+
if (buffer.byteLength <= Math.max(0, Number(configured))) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
const bytes = new Uint8Array(buffer);
|
|
231
|
+
const { encoding } = resolveFileViewerTextEncoding(bytes, (_d = (_c = context === null || context === void 0 ? void 0 : context.options) === null || _c === void 0 ? void 0 : _c.text) === null || _d === void 0 ? void 0 : _d.encoding);
|
|
232
|
+
return encoding !== 'utf-16le' && encoding !== 'utf-16be';
|
|
184
233
|
};
|
|
185
234
|
const largeTextStyle = `
|
|
186
235
|
.code-viewer--virtual{height:100%;min-height:240px;display:flex;flex-direction:column;overflow:hidden}
|
|
@@ -201,22 +250,24 @@ const largeTextStyle = `
|
|
|
201
250
|
.code-line-segments span{min-width:64px;color:var(--code-muted);font-size:11px;line-height:1;text-align:center}
|
|
202
251
|
`;
|
|
203
252
|
export default async function renderLargeText(buffer, target, type = 'txt', context) {
|
|
204
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
253
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
205
254
|
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
206
255
|
const documentRef = target.ownerDocument;
|
|
207
|
-
const
|
|
208
|
-
const
|
|
256
|
+
const sourceBytes = new Uint8Array(buffer);
|
|
257
|
+
const source = resolveFileViewerTextEncoding(sourceBytes, (_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.encoding);
|
|
258
|
+
const bytes = sourceBytes.subarray(source.bomLength);
|
|
259
|
+
const configuredSegmentBytes = (_d = (_c = context === null || context === void 0 ? void 0 : context.options) === null || _c === void 0 ? void 0 : _c.text) === null || _d === void 0 ? void 0 : _d.maxRenderedLineBytes;
|
|
209
260
|
const segmentBytes = Number.isFinite(configuredSegmentBytes)
|
|
210
261
|
? clamp(Math.trunc(Number(configuredSegmentBytes)), 1024, 256 * 1024)
|
|
211
262
|
: DEFAULT_LARGE_TEXT_LINE_SEGMENT_BYTES;
|
|
212
|
-
const configuredOverscan = (
|
|
263
|
+
const configuredOverscan = (_f = (_e = context === null || context === void 0 ? void 0 : context.options) === null || _e === void 0 ? void 0 : _e.text) === null || _f === void 0 ? void 0 : _f.virtualOverscanLines;
|
|
213
264
|
const overscan = Number.isFinite(configuredOverscan)
|
|
214
265
|
? clamp(Math.trunc(Number(configuredOverscan)), 2, 100)
|
|
215
266
|
: DEFAULT_LARGE_TEXT_OVERSCAN_LINES;
|
|
216
|
-
const showToolbar = ((
|
|
267
|
+
const showToolbar = ((_h = (_g = context === null || context === void 0 ? void 0 : context.options) === null || _g === void 0 ? void 0 : _g.text) === null || _h === void 0 ? void 0 : _h.toolbar) !== false;
|
|
217
268
|
// Undefined preserves the large-text renderer's pre-option behavior. An
|
|
218
269
|
// explicit boolean has the same meaning in both regular and virtual views.
|
|
219
|
-
const showLineNumbers = ((
|
|
270
|
+
const showLineNumbers = ((_k = (_j = context === null || context === void 0 ? void 0 : context.options) === null || _j === void 0 ? void 0 : _j.text) === null || _k === void 0 ? void 0 : _k.lineNumbers) !== false;
|
|
220
271
|
let disposed = false;
|
|
221
272
|
let zoom = 1;
|
|
222
273
|
let scheduledFrame = 0;
|
|
@@ -235,6 +286,7 @@ export default async function renderLargeText(buffer, target, type = 'txt', cont
|
|
|
235
286
|
root.dataset.viewerSearchProvider = 'code-virtual';
|
|
236
287
|
root.dataset.textToolbar = String(showToolbar);
|
|
237
288
|
root.dataset.lineNumbers = String(showLineNumbers);
|
|
289
|
+
root.dataset.textEncoding = source.encoding;
|
|
238
290
|
const toolbar = documentRef.createElement('div');
|
|
239
291
|
toolbar.className = 'code-toolbar';
|
|
240
292
|
const extensionLabel = documentRef.createElement('span');
|
|
@@ -250,8 +302,8 @@ export default async function renderLargeText(buffer, target, type = 'txt', cont
|
|
|
250
302
|
root.append(toolbar);
|
|
251
303
|
}
|
|
252
304
|
target.replaceChildren(style, root);
|
|
253
|
-
(
|
|
254
|
-
const index = await buildLargeTextIndex(bytes, target, progress => {
|
|
305
|
+
(_l = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _l === void 0 ? void 0 : _l.call(context);
|
|
306
|
+
const index = await buildLargeTextIndex(bytes, source.encoding, target, progress => {
|
|
255
307
|
if (!disposed) {
|
|
256
308
|
status.textContent = t('text.code.indexingLargeFile', { progress });
|
|
257
309
|
}
|
|
@@ -461,13 +513,31 @@ export default async function renderLargeText(buffer, target, type = 'txt', cont
|
|
|
461
513
|
const maxMatches = Math.max(1, options.maxMatches || DEFAULT_FILE_VIEWER_SEARCH_MAX_MATCHES);
|
|
462
514
|
const expression = createLargeTextSearchRegExp(query, options);
|
|
463
515
|
const encoder = new TextEncoder();
|
|
464
|
-
const encodedQueryBytes =
|
|
516
|
+
const encodedQueryBytes = index.encoding === 'gb18030'
|
|
517
|
+
? query.length * 4
|
|
518
|
+
: encoder.encode(query).byteLength;
|
|
465
519
|
const overlap = clamp(encodedQueryBytes * 2, 256, 64 * 1024);
|
|
520
|
+
const advanceBytesForCharacters = (start, end, characterCount) => {
|
|
521
|
+
if (index.encoding !== 'gb18030') {
|
|
522
|
+
const decoded = createFileViewerTextDecoder(index.encoding).decode(index.bytes.subarray(start, end));
|
|
523
|
+
return encoder.encode(decoded.slice(0, characterCount)).byteLength;
|
|
524
|
+
}
|
|
525
|
+
let cursor = start;
|
|
526
|
+
let characters = 0;
|
|
527
|
+
while (cursor < end && characters < characterCount) {
|
|
528
|
+
const size = gb18030UnitLength(index.bytes, cursor, end);
|
|
529
|
+
characters += size === 4
|
|
530
|
+
? createFileViewerTextDecoder('gb18030').decode(index.bytes.subarray(cursor, cursor + size)).length
|
|
531
|
+
: 1;
|
|
532
|
+
cursor += size;
|
|
533
|
+
}
|
|
534
|
+
return cursor - start;
|
|
535
|
+
};
|
|
466
536
|
for (let primaryStart = 0; primaryStart < index.bytes.byteLength && matches.length < maxMatches;) {
|
|
467
|
-
const primaryEnd = Math.min(index.bytes.byteLength, primaryStart + LARGE_TEXT_SEARCH_CHUNK_BYTES);
|
|
468
|
-
const decodeStart =
|
|
469
|
-
const decodeEnd =
|
|
470
|
-
const text =
|
|
537
|
+
const primaryEnd = alignTextBoundary(index, primaryStart, Math.min(index.bytes.byteLength, primaryStart + LARGE_TEXT_SEARCH_CHUNK_BYTES), index.bytes.byteLength);
|
|
538
|
+
const decodeStart = primaryStart;
|
|
539
|
+
const decodeEnd = alignTextBoundary(index, primaryStart, Math.min(index.bytes.byteLength, primaryEnd + overlap), index.bytes.byteLength);
|
|
540
|
+
const text = createFileViewerTextDecoder(index.encoding).decode(index.bytes.subarray(decodeStart, decodeEnd));
|
|
471
541
|
let lastCharacterOffset = 0;
|
|
472
542
|
let byteCursor = decodeStart;
|
|
473
543
|
expression.lastIndex = 0;
|
|
@@ -477,9 +547,9 @@ export default async function renderLargeText(buffer, target, type = 'txt', cont
|
|
|
477
547
|
expression.lastIndex += 1;
|
|
478
548
|
continue;
|
|
479
549
|
}
|
|
480
|
-
byteCursor +=
|
|
550
|
+
byteCursor += advanceBytesForCharacters(byteCursor, decodeEnd, match.index - lastCharacterOffset);
|
|
481
551
|
const matchByteOffset = byteCursor;
|
|
482
|
-
byteCursor +=
|
|
552
|
+
byteCursor += advanceBytesForCharacters(byteCursor, decodeEnd, match[0].length);
|
|
483
553
|
lastCharacterOffset = match.index + match[0].length;
|
|
484
554
|
if (matchByteOffset < primaryStart || matchByteOffset >= primaryEnd) {
|
|
485
555
|
continue;
|
|
@@ -542,7 +612,7 @@ export default async function renderLargeText(buffer, target, type = 'txt', cont
|
|
|
542
612
|
getState: getZoomState,
|
|
543
613
|
subscribe: zoomEmitter.subscribe
|
|
544
614
|
});
|
|
545
|
-
(
|
|
615
|
+
(_m = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _m === void 0 ? void 0 : _m.call(context, { print: false, exportHtml: false });
|
|
546
616
|
viewport.addEventListener('scroll', scheduleRender, { passive: true });
|
|
547
617
|
viewport.addEventListener('click', event => {
|
|
548
618
|
var _a, _b;
|
|
@@ -568,7 +638,7 @@ export default async function renderLargeText(buffer, target, type = 'txt', cont
|
|
|
568
638
|
lineSegments.set(lineIndex, clamp(next, 0, segmentCount - 1));
|
|
569
639
|
renderWindow(true);
|
|
570
640
|
});
|
|
571
|
-
const ResizeObserverCtor = (
|
|
641
|
+
const ResizeObserverCtor = (_o = getWindow(target)) === null || _o === void 0 ? void 0 : _o.ResizeObserver;
|
|
572
642
|
const resizeObserver = ResizeObserverCtor
|
|
573
643
|
? new ResizeObserverCtor(() => {
|
|
574
644
|
updateSpacerHeight();
|
package/dist/markdown.js
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { marked } from 'marked';
|
|
2
|
-
import
|
|
2
|
+
import createDOMPurify from 'dompurify';
|
|
3
|
+
import { createFileViewerZoomChangeEmitter as createZoomChangeEmitter, decodeFileViewerTextBuffer, registerFileViewerZoomProvider, resolveFileViewerFitScale, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
|
|
4
|
+
const createSafeTextFragment = (documentRef, value) => {
|
|
5
|
+
const fragment = documentRef.createDocumentFragment();
|
|
6
|
+
fragment.append(documentRef.createTextNode(value));
|
|
7
|
+
return fragment;
|
|
8
|
+
};
|
|
9
|
+
const sanitizeMarkdownHtml = (documentRef, html) => {
|
|
10
|
+
const windowRef = documentRef.defaultView;
|
|
11
|
+
if (!windowRef) {
|
|
12
|
+
return createSafeTextFragment(documentRef, html);
|
|
13
|
+
}
|
|
14
|
+
const purifier = createDOMPurify(windowRef);
|
|
15
|
+
if (!purifier.isSupported) {
|
|
16
|
+
return createSafeTextFragment(documentRef, html);
|
|
17
|
+
}
|
|
18
|
+
return purifier.sanitize(html, {
|
|
19
|
+
RETURN_DOM_FRAGMENT: true,
|
|
20
|
+
USE_PROFILES: { html: true },
|
|
21
|
+
ADD_ATTR: ['target'],
|
|
22
|
+
FORBID_TAGS: ['style', 'iframe', 'object', 'embed', 'form'],
|
|
23
|
+
FORBID_ATTR: ['style', 'srcdoc'],
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
const hardenMarkdownLinks = (root) => {
|
|
27
|
+
root.querySelectorAll('a[target]').forEach(anchor => {
|
|
28
|
+
if ((anchor.getAttribute('target') || '').trim().toLowerCase() === '_blank') {
|
|
29
|
+
anchor.rel = 'noopener noreferrer';
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
|
3
33
|
const markdownStyle = `
|
|
4
34
|
.markdown-viewer{min-height:100%;padding:28px 16px 48px;background:var(--file-viewer-render-surface-background,#eef1f4);overflow:auto;box-sizing:border-box}
|
|
5
35
|
.markdown-body{color-scheme:light;--bgColor-default:#fff;--bgColor-muted:#f6f8fa;--bgColor-neutral-muted:#818b981f;--borderColor-default:#d1d9e0;--borderColor-muted:#d1d9e0b3;--borderColor-neutral-muted:#d1d9e0b3;--fgColor-default:#1f2328;--fgColor-muted:#59636e;--fgColor-accent:#0969da;background:var(--bgColor-default);border:1px solid rgba(20,35,53,.1);border-radius:12px;margin:0 auto;box-sizing:border-box;min-width:200px;max-width:var(--markdown-max-width,980px);padding:var(--markdown-padding,45px);color:var(--fgColor-default);font-size:var(--markdown-font-size,16px);box-shadow:0 18px 42px rgba(15,23,42,.1)}
|
|
@@ -166,8 +196,8 @@ export const stripMarkdownFrontmatter = (text) => {
|
|
|
166
196
|
return input.slice(match.index + match[0].length).replace(/^\r?\n/, '');
|
|
167
197
|
};
|
|
168
198
|
export default async function renderMarkdown(buffer, target, context) {
|
|
169
|
-
var _a;
|
|
170
|
-
const text =
|
|
199
|
+
var _a, _b, _c;
|
|
200
|
+
const text = decodeFileViewerTextBuffer(buffer, (_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.encoding).text;
|
|
171
201
|
let zoom = 1;
|
|
172
202
|
const zoomEmitter = createZoomChangeEmitter();
|
|
173
203
|
const root = document.createElement('div');
|
|
@@ -175,11 +205,13 @@ export default async function renderMarkdown(buffer, target, context) {
|
|
|
175
205
|
root.dataset.viewerZoomProvider = 'markdown';
|
|
176
206
|
const article = document.createElement('article');
|
|
177
207
|
article.className = 'markdown-body';
|
|
178
|
-
|
|
208
|
+
const renderedHtml = await marked(stripMarkdownFrontmatter(text));
|
|
209
|
+
article.append(sanitizeMarkdownHtml(article.ownerDocument, renderedHtml));
|
|
210
|
+
hardenMarkdownLinks(article);
|
|
179
211
|
applyMarkdownZoom(root, zoom);
|
|
180
212
|
root.append(article);
|
|
181
213
|
target.replaceChildren(createStyle(), root);
|
|
182
|
-
await renderEmbeddedMermaid(article, (
|
|
214
|
+
await renderEmbeddedMermaid(article, (_c = context === null || context === void 0 ? void 0 : context.options) === null || _c === void 0 ? void 0 : _c.theme);
|
|
183
215
|
const baseContentHeight = Math.max(article.scrollHeight || 0, article.offsetHeight || 0, 0);
|
|
184
216
|
const getZoomState = () => ({
|
|
185
217
|
scale: zoom,
|
package/dist/patch.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type FileRenderContext, type FileViewerRenderedInstance } from '@file-viewer/core';
|
|
2
|
-
export default function renderPatch(buffer: ArrayBuffer, target: HTMLDivElement, type?: string,
|
|
2
|
+
export default function renderPatch(buffer: ArrayBuffer, target: HTMLDivElement, type?: string, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;
|
package/dist/patch.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createFileViewerZoomChangeEmitter as createZoomChangeEmitter,
|
|
1
|
+
import { createFileViewerZoomChangeEmitter as createZoomChangeEmitter, decodeFileViewerTextBuffer, registerFileViewerZoomProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
|
|
2
2
|
import { html as diffToHtml } from 'diff2html';
|
|
3
3
|
const patchStyle = `
|
|
4
4
|
.patch-viewer{min-height:100%;--patch-bg:#f6f8fa;--patch-surface:#fff;--patch-border:rgba(31,35,40,.12);--patch-text:#24292f;--patch-muted:#57606a;--patch-add:#dafbe1;--patch-del:#ffebe9;--patch-info:#ddf4ff;--patch-font-size:13px;background:var(--patch-bg);color:var(--patch-text);box-sizing:border-box}
|
|
@@ -64,9 +64,10 @@ const escapeHtml = (value) => {
|
|
|
64
64
|
return entities[char];
|
|
65
65
|
});
|
|
66
66
|
};
|
|
67
|
-
export default async function renderPatch(buffer, target, type = 'patch',
|
|
67
|
+
export default async function renderPatch(buffer, target, type = 'patch', context) {
|
|
68
|
+
var _a, _b;
|
|
68
69
|
const documentRef = target.ownerDocument || document;
|
|
69
|
-
const text =
|
|
70
|
+
const text = decodeFileViewerTextBuffer(buffer, (_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.encoding).text;
|
|
70
71
|
let zoom = 1;
|
|
71
72
|
const zoomEmitter = createZoomChangeEmitter();
|
|
72
73
|
const root = createElement(documentRef, 'div', 'patch-viewer');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-text",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone code, text, Markdown, patch diff, and Git bundle renderer plugin for File Viewer.",
|
|
@@ -57,12 +57,13 @@
|
|
|
57
57
|
"LICENSE"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@file-viewer/core": "2.
|
|
60
|
+
"@file-viewer/core": "2.3.0",
|
|
61
61
|
"diff2html": "^3.4.56",
|
|
62
62
|
"highlight.js": "^11.11.1",
|
|
63
63
|
"marked": "^18.0.5",
|
|
64
|
-
"mermaid": "^11.
|
|
65
|
-
"pako": "^2.1.0"
|
|
64
|
+
"mermaid": "^11.16.1",
|
|
65
|
+
"pako": "^2.1.0",
|
|
66
|
+
"dompurify": "^3.4.13"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"typescript": "^6.0.3"
|