@stll/folio-core 0.44.0 → 0.45.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/ai-edits/__fixtures__/paragraphs.js +2 -2
- package/dist/ai-edits/headless.js +1 -0
- package/dist/compare/content-alignment.js +78 -53
- package/dist/compare/inline-atoms.js +34 -20
- package/dist/content-controls/mutateContentControls.js +4 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -8
- package/dist/document-operations.js +14 -3
- package/dist/docx/borderParser.js +5 -5
- package/dist/docx/commentParser.js +47 -36
- package/dist/docx/commentThreadKey.d.ts +18 -0
- package/dist/docx/commentThreadKey.js +22 -0
- package/dist/docx/diagramPreview.js +87 -27
- package/dist/docx/groupDrawingParser.js +3 -3
- package/dist/docx/hyperlinkParser.js +2 -2
- package/dist/docx/imageParser.d.ts +9 -1
- package/dist/docx/imageParser.js +58 -12
- package/dist/docx/imageRawXml.d.ts +14 -1
- package/dist/docx/imageRawXml.js +30 -6
- package/dist/docx/mathToMathml.js +12 -14
- package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
- package/dist/docx/nonVisualDrawingProps.js +46 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +3 -0
- package/dist/docx/parser.js +2 -2
- package/dist/docx/previewBudget.d.ts +64 -0
- package/dist/docx/previewBudget.js +88 -0
- package/dist/docx/revisionIdNormalization.js +17 -5
- package/dist/docx/rezip.js +17 -18
- package/dist/docx/sdtPropertiesPatch.js +24 -18
- package/dist/docx/sectionReferenceHistory.js +2 -2
- package/dist/docx/selectiveSave.js +6 -6
- package/dist/docx/serializer/blockSdtSerializer.js +38 -26
- package/dist/docx/serializer/borderSerializer.d.ts +1 -1
- package/dist/docx/serializer/borderSerializer.js +13 -12
- package/dist/docx/serializer/commentSerializer.d.ts +41 -16
- package/dist/docx/serializer/commentSerializer.js +82 -85
- package/dist/docx/serializer/fontTableSerializer.js +6 -6
- package/dist/docx/serializer/headerFooterSerializer.js +5 -5
- package/dist/docx/serializer/markupRangeAttributes.js +2 -2
- package/dist/docx/serializer/numberingSerializer.js +7 -6
- package/dist/docx/serializer/paragraphSerializer.js +19 -18
- package/dist/docx/serializer/partNamespaces.js +2 -2
- package/dist/docx/serializer/runSerializer.js +48 -28
- package/dist/docx/serializer/sectionPropertiesSerializer.js +11 -10
- package/dist/docx/serializer/settingsSerializer.js +4 -3
- package/dist/docx/serializer/stylesSerializer.js +6 -6
- package/dist/docx/serializer/tableSerializer.js +10 -9
- package/dist/docx/serializer/textFormattingSerializer.js +29 -28
- package/dist/docx/serializer/themeSerializer.js +6 -6
- package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
- package/dist/docx/serializer/xmlUtils.d.ts +1 -2
- package/dist/docx/serializer/xmlUtils.js +1 -13
- package/dist/docx/server/boundedArchive.d.ts +12 -0
- package/dist/docx/server/boundedArchive.js +20 -1
- package/dist/docx/server/validateDocxConformance.js +22 -1
- package/dist/docx/shapeParser.js +7 -5
- package/dist/docx/textBoxParser.js +7 -2
- package/dist/docx/unzip.d.ts +23 -0
- package/dist/docx/unzip.js +32 -22
- package/dist/docx/verbatimCapture.js +1 -1
- package/dist/docx/vmlImageParser.js +3 -2
- package/dist/docx/vmlPreview.d.ts +1 -3
- package/dist/docx/vmlPreview.js +2 -30
- package/dist/docx/xmlParser.d.ts +16 -1
- package/dist/docx/xmlParser.js +56 -26
- package/dist/docx/xmlResourceLimits.d.ts +89 -9
- package/dist/docx/xmlResourceLimits.js +105 -24
- package/dist/internal/paragraphFormattingSerialization.js +3 -2
- package/dist/layout-painter/renderImage.js +4 -3
- package/dist/layout-painter/renderParagraph.js +4 -3
- package/dist/managers/autoSaveCodec.js +2 -8
- package/dist/markdown/images.js +1 -4
- package/dist/prosemirror/attrs/index.js +69 -0
- package/dist/prosemirror/commands/image.js +1 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +69 -29
- package/dist/prosemirror/conversion/toProseDoc.js +83 -19
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +4 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +7 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +8 -4
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +6 -3
- package/dist/prosemirror/paragraphFormattingProvenance.js +12 -3
- package/dist/prosemirror/schema/nodes.d.ts +50 -1
- package/dist/utils/base64.d.ts +36 -0
- package/dist/utils/base64.js +40 -0
- package/dist/utils/clipboard.js +2 -1
- package/dist/utils/units.d.ts +10 -1
- package/dist/utils/units.js +12 -1
- package/dist/utils/urlSecurity.d.ts +8 -2
- package/dist/utils/urlSecurity.js +21 -3
- package/package.json +2 -2
|
@@ -264,6 +264,25 @@ type ImagePositionAttrs = {
|
|
|
264
264
|
align?: NonNullable<document_d_exports.ImagePosition["vertical"]["alignment"]>;
|
|
265
265
|
};
|
|
266
266
|
};
|
|
267
|
+
/**
|
|
268
|
+
* The EMUs a drawing's pixel attributes were projected from, keyed by the
|
|
269
|
+
* pixel attribute each one became.
|
|
270
|
+
*
|
|
271
|
+
* EMU → px → EMU does not land back on the same number: a size rounds to whole
|
|
272
|
+
* pixels, a stroke or an inset to two. Without the authored value beside the
|
|
273
|
+
* projected one, opening a document and saving it again moved every drawing
|
|
274
|
+
* off the number its author wrote. `fromProseDoc` writes the authored EMU back
|
|
275
|
+
* while the pixel attribute still projects from it, and converts the pixel
|
|
276
|
+
* attribute once an editor command has moved it.
|
|
277
|
+
*
|
|
278
|
+
* A key carries `undefined` when the source authored no such value, so an
|
|
279
|
+
* absent value stays absent rather than acquiring one the document never had.
|
|
280
|
+
*/
|
|
281
|
+
type AuthoredEmuAttrs<Key extends string> = { readonly [K in Key]?: number | undefined; };
|
|
282
|
+
/** The pixel attributes a drawing's `wp:wrap*` insets are projected into. */
|
|
283
|
+
type WrapDistanceAttr = "distTop" | "distBottom" | "distLeft" | "distRight";
|
|
284
|
+
/** The pixel attributes a text box's internal margins are projected into. */
|
|
285
|
+
type TextBoxMarginAttr = "marginTop" | "marginBottom" | "marginLeft" | "marginRight";
|
|
267
286
|
/**
|
|
268
287
|
* Image node attributes
|
|
269
288
|
*/
|
|
@@ -320,6 +339,16 @@ type ImageAttrs = {
|
|
|
320
339
|
position?: ImagePositionAttrs;
|
|
321
340
|
/** Use the containing table cell as the anchor's positioning scope (the OOXML default). */
|
|
322
341
|
layoutInCell?: boolean;
|
|
342
|
+
/**
|
|
343
|
+
* The image carries no information, so assistive technology skips it
|
|
344
|
+
* (`wp:docPr`'s decorative extension). Not {@link hidden}: a decorative
|
|
345
|
+
* image is still displayed.
|
|
346
|
+
*/
|
|
347
|
+
decorative?: boolean;
|
|
348
|
+
/** `wp:docPr @hidden`: the drawing is not displayed. */
|
|
349
|
+
hidden?: boolean;
|
|
350
|
+
/** `wp:docPr` extensions folio does not model, carried through verbatim. */
|
|
351
|
+
docPrExtensions?: string[];
|
|
323
352
|
/**
|
|
324
353
|
* Authored `a:graphicFrameLocks`. Carried through the editor so a resize,
|
|
325
354
|
* which forces the serializer to regenerate DrawingML, cannot silently
|
|
@@ -328,6 +357,8 @@ type ImageAttrs = {
|
|
|
328
357
|
frameLocks?: document_d_exports.ImageFrameLocks;
|
|
329
358
|
/** Border width in pixels */
|
|
330
359
|
borderWidth?: number;
|
|
360
|
+
/** The EMUs behind `width`, `height`, `borderWidth` and the wrap insets. */
|
|
361
|
+
_docxAuthoredEmu?: AuthoredEmuAttrs<"width" | "height" | "borderWidth" | WrapDistanceAttr>;
|
|
331
362
|
/** Border color as CSS color string */
|
|
332
363
|
borderColor?: string;
|
|
333
364
|
/** Border style (CSS border-style value) */
|
|
@@ -468,6 +499,12 @@ type ShapeAttrs = {
|
|
|
468
499
|
geometryAdjustments?: string;
|
|
469
500
|
/** Unique identifier */
|
|
470
501
|
shapeId?: string;
|
|
502
|
+
/** Authored non-visual drawing name (`wp:docPr@name` / `wps:cNvPr@name`) */
|
|
503
|
+
shapeName?: string;
|
|
504
|
+
/** Alt text for accessibility (`wp:docPr@descr`) */
|
|
505
|
+
alt?: string;
|
|
506
|
+
/** Authored non-visual drawing title (`wp:docPr@title`) */
|
|
507
|
+
title?: string;
|
|
471
508
|
/** Width in pixels */
|
|
472
509
|
width?: number;
|
|
473
510
|
/** Height in pixels */
|
|
@@ -494,6 +531,8 @@ type ShapeAttrs = {
|
|
|
494
531
|
outlineStyle?: OutlineStyleAttr;
|
|
495
532
|
/** Line cap */
|
|
496
533
|
outlineCap?: NonNullable<document_d_exports.ShapeOutline["cap"]>;
|
|
534
|
+
/** Line join */
|
|
535
|
+
outlineJoin?: NonNullable<document_d_exports.ShapeOutline["join"]>;
|
|
497
536
|
/** Head arrow/end marker */
|
|
498
537
|
outlineHeadEnd?: NonNullable<document_d_exports.ShapeOutline["headEnd"]>;
|
|
499
538
|
/** Tail arrow/end marker */
|
|
@@ -538,6 +577,8 @@ type ShapeAttrs = {
|
|
|
538
577
|
* census).
|
|
539
578
|
*/
|
|
540
579
|
_docxRunFormatting?: document_d_exports.TextFormatting;
|
|
580
|
+
/** The EMUs behind `width`, `height`, `outlineWidth` and the wrap insets. */
|
|
581
|
+
_docxAuthoredEmu?: AuthoredEmuAttrs<"width" | "height" | "outlineWidth" | WrapDistanceAttr>;
|
|
541
582
|
};
|
|
542
583
|
/**
|
|
543
584
|
* Text box node attributes
|
|
@@ -551,6 +592,8 @@ type TextBoxAttrs = {
|
|
|
551
592
|
width?: number;
|
|
552
593
|
/** Height in pixels */
|
|
553
594
|
height?: number;
|
|
595
|
+
/** The EMUs behind the size, `outlineWidth`, the wrap insets and the margins. */
|
|
596
|
+
_docxAuthoredEmu?: AuthoredEmuAttrs<"width" | "height" | "outlineWidth" | WrapDistanceAttr | TextBoxMarginAttr>;
|
|
554
597
|
/** Text fitting behavior */
|
|
555
598
|
autoFit?: document_d_exports.ShapeTextBody["autoFit"];
|
|
556
599
|
/** Authored DrawingML WordArt metadata. */
|
|
@@ -559,6 +602,12 @@ type TextBoxAttrs = {
|
|
|
559
602
|
textWrap?: document_d_exports.ShapeTextBody["textWrap"];
|
|
560
603
|
/** Unique identifier */
|
|
561
604
|
textBoxId?: string;
|
|
605
|
+
/** Authored non-visual drawing name (`wp:docPr@name` / `wps:cNvPr@name`) */
|
|
606
|
+
textBoxName?: string;
|
|
607
|
+
/** Alt text for accessibility (`wp:docPr@descr`) */
|
|
608
|
+
alt?: string;
|
|
609
|
+
/** Authored non-visual drawing title (`wp:docPr@title`) */
|
|
610
|
+
title?: string;
|
|
562
611
|
/** Fill color as CSS color */
|
|
563
612
|
fillColor?: string;
|
|
564
613
|
/** Outline width in pixels */
|
|
@@ -836,4 +885,4 @@ type TableCellAttrs = {
|
|
|
836
885
|
_docxVMergeContinuationCells?: unknown;
|
|
837
886
|
};
|
|
838
887
|
//#endregion
|
|
839
|
-
export { BlockSdtAttrs, BookmarkBoundaryAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PageBreakRunAttrs, ParagraphAttrs, ParagraphPropertyChangeAttrs, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs, TextBoxTextBodyContentState };
|
|
888
|
+
export { AuthoredEmuAttrs, BlockSdtAttrs, BookmarkBoundaryAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PageBreakRunAttrs, ParagraphAttrs, ParagraphPropertyChangeAttrs, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs, TextBoxTextBodyContentState };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/utils/base64.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The package's one bytes-to-base64 encoder.
|
|
4
|
+
*
|
|
5
|
+
* Every call site that spelled this itself got a different answer to the same
|
|
6
|
+
* two questions, and one of them got the first question wrong:
|
|
7
|
+
*
|
|
8
|
+
* - `btoa(new TextDecoder("latin1").decode(bytes))` is not a binary string.
|
|
9
|
+
* The Encoding standard maps the `latin1` label to windows-1252, so bytes
|
|
10
|
+
* 0x80-0x9F decode to characters outside Latin-1 and `btoa` throws
|
|
11
|
+
* `InvalidCharacterError` on them. Ordinary image bytes contain those values,
|
|
12
|
+
* so the browser path of that spelling fails on real input.
|
|
13
|
+
* - `String.fromCharCode(...chunk)` is correct but spreads a chunk's worth of
|
|
14
|
+
* arguments per call, and the intermediate binary string is as large as the
|
|
15
|
+
* input.
|
|
16
|
+
*
|
|
17
|
+
* Neither question has to be asked per call site, so it is asked here once.
|
|
18
|
+
* The runtime's own encoder answers it when the runtime has one, and the
|
|
19
|
+
* portable encoder below answers it when not; both produce canonical base64,
|
|
20
|
+
* so the choice is invisible in the output.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Encode into exactly one intermediate buffer: ASCII codes are written into a
|
|
24
|
+
* single array and decoded once, so a megabyte-scale input leaves the output
|
|
25
|
+
* string and nothing else.
|
|
26
|
+
*
|
|
27
|
+
* Exported because the runtimes the tests run on all carry a native encoder,
|
|
28
|
+
* and the fallback is the branch the browsers that lack one take.
|
|
29
|
+
*/
|
|
30
|
+
declare const encodeBase64Portable: (bytes: Uint8Array) => string;
|
|
31
|
+
/** Encode bytes as canonical, padded, standard-alphabet base64. */
|
|
32
|
+
declare const bytesToBase64: (bytes: Uint8Array) => string;
|
|
33
|
+
/** Encode bytes as a `data:` URL with the given media type. */
|
|
34
|
+
declare const bytesToDataUrl: (bytes: Uint8Array, mimeType: string) => string;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { bytesToBase64, bytesToDataUrl, encodeBase64Portable };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/utils/base64.ts
|
|
2
|
+
const BASE64_CODES = Uint8Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", (character) => character.charCodeAt(0));
|
|
3
|
+
const BASE64_PAD = 61;
|
|
4
|
+
/**
|
|
5
|
+
* Encode into exactly one intermediate buffer: ASCII codes are written into a
|
|
6
|
+
* single array and decoded once, so a megabyte-scale input leaves the output
|
|
7
|
+
* string and nothing else.
|
|
8
|
+
*
|
|
9
|
+
* Exported because the runtimes the tests run on all carry a native encoder,
|
|
10
|
+
* and the fallback is the branch the browsers that lack one take.
|
|
11
|
+
*/
|
|
12
|
+
const encodeBase64Portable = (bytes) => {
|
|
13
|
+
const groups = Math.ceil(bytes.length / 3);
|
|
14
|
+
const encoded = new Uint8Array(groups * 4);
|
|
15
|
+
let read = 0;
|
|
16
|
+
let write = 0;
|
|
17
|
+
for (; read + 2 < bytes.length; read += 3) {
|
|
18
|
+
const triple = bytes[read] << 16 | bytes[read + 1] << 8 | bytes[read + 2];
|
|
19
|
+
encoded[write] = BASE64_CODES[triple >> 18 & 63];
|
|
20
|
+
encoded[write + 1] = BASE64_CODES[triple >> 12 & 63];
|
|
21
|
+
encoded[write + 2] = BASE64_CODES[triple >> 6 & 63];
|
|
22
|
+
encoded[write + 3] = BASE64_CODES[triple & 63];
|
|
23
|
+
write += 4;
|
|
24
|
+
}
|
|
25
|
+
const remaining = bytes.length - read;
|
|
26
|
+
if (remaining > 0) {
|
|
27
|
+
const tail = bytes[read] << 16 | (remaining === 2 ? bytes[read + 1] << 8 : 0);
|
|
28
|
+
encoded[write] = BASE64_CODES[tail >> 18 & 63];
|
|
29
|
+
encoded[write + 1] = BASE64_CODES[tail >> 12 & 63];
|
|
30
|
+
encoded[write + 2] = remaining === 2 ? BASE64_CODES[tail >> 6 & 63] : BASE64_PAD;
|
|
31
|
+
encoded[write + 3] = BASE64_PAD;
|
|
32
|
+
}
|
|
33
|
+
return new TextDecoder().decode(encoded);
|
|
34
|
+
};
|
|
35
|
+
/** Encode bytes as canonical, padded, standard-alphabet base64. */
|
|
36
|
+
const bytesToBase64 = ("toBase64" in Uint8Array.prototype ? (bytes) => bytes.toBase64() : void 0) ?? encodeBase64Portable;
|
|
37
|
+
/** Encode bytes as a `data:` URL with the given media type. */
|
|
38
|
+
const bytesToDataUrl = (bytes, mimeType) => `data:${mimeType};base64,${bytesToBase64(bytes)}`;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { bytesToBase64, bytesToDataUrl, encodeBase64Portable };
|
package/dist/utils/clipboard.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { htmlCommentEnd } from "./htmlComments.js";
|
|
2
2
|
import { stripXmlDeclarations } from "./stripXmlDeclarations.js";
|
|
3
|
+
import { sanitizeXmlCharacters } from "@stll/docx-core";
|
|
3
4
|
import createDOMPurify from "dompurify";
|
|
4
5
|
//#region src/utils/clipboard.ts
|
|
5
6
|
/**
|
|
@@ -567,7 +568,7 @@ function createTextRun(text, formatting) {
|
|
|
567
568
|
...formatting !== void 0 ? { formatting } : {},
|
|
568
569
|
content: [{
|
|
569
570
|
type: "text",
|
|
570
|
-
text
|
|
571
|
+
text: sanitizeXmlCharacters(text)
|
|
571
572
|
}]
|
|
572
573
|
};
|
|
573
574
|
}
|
package/dist/utils/units.d.ts
CHANGED
|
@@ -48,6 +48,15 @@ declare function emuToPixels(emu: number | undefined | null): number;
|
|
|
48
48
|
* floating-point drift (e.g. 52 px → 495299.99999999994) out of the document.
|
|
49
49
|
*/
|
|
50
50
|
declare function pixelsToEmu(px: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* Convert EMUs to pixels for a stroke width.
|
|
53
|
+
*
|
|
54
|
+
* Strokes are sub-pixel, so unlike a box size they keep two decimals rather
|
|
55
|
+
* than rounding to whole pixels. The projection is still lossy: a consumer that
|
|
56
|
+
* has to write the document's own number back carries the authored EMU beside
|
|
57
|
+
* the pixels rather than converting these back.
|
|
58
|
+
*/
|
|
59
|
+
declare function emuToStrokePixels(emu: number): number;
|
|
51
60
|
/**
|
|
52
61
|
* Convert EMUs to twips. Twips are integer-typed in OOXML; round here.
|
|
53
62
|
*/
|
|
@@ -96,4 +105,4 @@ declare function clamp(value: number, min: number, max: number): number;
|
|
|
96
105
|
*/
|
|
97
106
|
declare function formatPx(px: number): string;
|
|
98
107
|
//#endregion
|
|
99
|
-
export { AUTO_PARAGRAPH_SPACING_PX, PIXELS_PER_INCH, TWIPS_PER_INCH, clamp, eighthsToPixels, emuToPixels, emuToTwips, formatPx, halfPointsToPixels, halfPointsToPoints, pixelsToEmu, pixelsToTwips, pointsToHalfPoints, pointsToPixels, roundPixels, twipsToEmu, twipsToPixels };
|
|
108
|
+
export { AUTO_PARAGRAPH_SPACING_PX, PIXELS_PER_INCH, TWIPS_PER_INCH, clamp, eighthsToPixels, emuToPixels, emuToStrokePixels, emuToTwips, formatPx, halfPointsToPixels, halfPointsToPoints, pixelsToEmu, pixelsToTwips, pointsToHalfPoints, pointsToPixels, roundPixels, twipsToEmu, twipsToPixels };
|
package/dist/utils/units.js
CHANGED
|
@@ -68,6 +68,17 @@ function pixelsToEmu(px) {
|
|
|
68
68
|
return Math.round(px / 96 * EMUS_PER_INCH);
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
+
* Convert EMUs to pixels for a stroke width.
|
|
72
|
+
*
|
|
73
|
+
* Strokes are sub-pixel, so unlike a box size they keep two decimals rather
|
|
74
|
+
* than rounding to whole pixels. The projection is still lossy: a consumer that
|
|
75
|
+
* has to write the document's own number back carries the authored EMU beside
|
|
76
|
+
* the pixels rather than converting these back.
|
|
77
|
+
*/
|
|
78
|
+
function emuToStrokePixels(emu) {
|
|
79
|
+
return roundPixels(emu / EMUS_PER_INCH * 96);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
71
82
|
* Convert EMUs to twips. Twips are integer-typed in OOXML; round here.
|
|
72
83
|
*/
|
|
73
84
|
function emuToTwips(emu) {
|
|
@@ -136,4 +147,4 @@ function formatPx(px) {
|
|
|
136
147
|
return `${roundPixels(px)}px`;
|
|
137
148
|
}
|
|
138
149
|
//#endregion
|
|
139
|
-
export { AUTO_PARAGRAPH_SPACING_PX, PIXELS_PER_INCH, TWIPS_PER_INCH, clamp, eighthsToPixels, emuToPixels, emuToTwips, formatPx, halfPointsToPixels, halfPointsToPoints, pixelsToEmu, pixelsToTwips, pointsToHalfPoints, pointsToPixels, roundPixels, twipsToEmu, twipsToPixels };
|
|
150
|
+
export { AUTO_PARAGRAPH_SPACING_PX, PIXELS_PER_INCH, TWIPS_PER_INCH, clamp, eighthsToPixels, emuToPixels, emuToStrokePixels, emuToTwips, formatPx, halfPointsToPixels, halfPointsToPoints, pixelsToEmu, pixelsToTwips, pointsToHalfPoints, pointsToPixels, roundPixels, twipsToEmu, twipsToPixels };
|
|
@@ -2,6 +2,12 @@ import { sanitizeExternalUrl } from "@stll/docx-core";
|
|
|
2
2
|
//#region src/utils/urlSecurity.d.ts
|
|
3
3
|
declare function normalizeUserUrl(rawUrl: string): string;
|
|
4
4
|
declare function isAllowedUserUrl(rawUrl: string): boolean;
|
|
5
|
-
|
|
5
|
+
type AnchorTargetAttrs = {
|
|
6
|
+
target: string;
|
|
7
|
+
rel: string;
|
|
8
|
+
};
|
|
9
|
+
declare function anchorTargetAttrs(authoredFrame: string | undefined): AnchorTargetAttrs;
|
|
10
|
+
/** `window.open` features carrying the same guarantees as {@link ANCHOR_REL}. */
|
|
11
|
+
declare function windowFeaturesFor({ rel }: AnchorTargetAttrs): string;
|
|
6
12
|
//#endregion
|
|
7
|
-
export { isAllowedUserUrl, normalizeUserUrl, sanitizeExternalUrl,
|
|
13
|
+
export { AnchorTargetAttrs, anchorTargetAttrs, isAllowedUserUrl, normalizeUserUrl, sanitizeExternalUrl, windowFeaturesFor };
|
|
@@ -23,8 +23,26 @@ function normalizeUserUrl(rawUrl) {
|
|
|
23
23
|
function isAllowedUserUrl(rawUrl) {
|
|
24
24
|
return normalizeUserUrl(rawUrl) !== "";
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The `target` and `rel` one authored frame may produce on a DOM anchor.
|
|
28
|
+
*
|
|
29
|
+
* A `w:tgtFrame` is a frame name, and a named frame addresses another browsing
|
|
30
|
+
* context: honouring an arbitrary one would let a document reach a frame it did
|
|
31
|
+
* not create. Every anchor and every navigation folio produces goes through
|
|
32
|
+
* here, so the clamp and the `rel` that must accompany `_blank` are decided
|
|
33
|
+
* once. The authored name itself stays in the model and is written back on
|
|
34
|
+
* save; clamping it at parse rewrote the document.
|
|
35
|
+
*/
|
|
36
|
+
const ANCHOR_REL = "noopener noreferrer";
|
|
37
|
+
function anchorTargetAttrs(authoredFrame) {
|
|
38
|
+
return {
|
|
39
|
+
target: authoredFrame && ALLOWED_TARGETS.has(authoredFrame) ? authoredFrame : "_blank",
|
|
40
|
+
rel: ANCHOR_REL
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** `window.open` features carrying the same guarantees as {@link ANCHOR_REL}. */
|
|
44
|
+
function windowFeaturesFor({ rel }) {
|
|
45
|
+
return rel.replaceAll(" ", ",");
|
|
28
46
|
}
|
|
29
47
|
function findFirstPathSeparatorIndex(value) {
|
|
30
48
|
return [
|
|
@@ -44,4 +62,4 @@ function startsWithPortSuffix(value) {
|
|
|
44
62
|
return index > 0 && (index === value.length || "/?#".includes(value[index]));
|
|
45
63
|
}
|
|
46
64
|
//#endregion
|
|
47
|
-
export { isAllowedUserUrl, normalizeUserUrl, sanitizeExternalUrl,
|
|
65
|
+
export { anchorTargetAttrs, isAllowedUserUrl, normalizeUserUrl, sanitizeExternalUrl, windowFeaturesFor };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
4
4
|
"description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"document-model",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"perf": "bun scripts/profile-editor.ts"
|
|
122
122
|
},
|
|
123
123
|
"dependencies": {
|
|
124
|
-
"@stll/docx-core": "^0.
|
|
124
|
+
"@stll/docx-core": "^0.23.0",
|
|
125
125
|
"@stll/docx-utils": "^0.1.0",
|
|
126
126
|
"@stll/template-conditions": ">=0.4.0 <1.0.0",
|
|
127
127
|
"better-result": "3.0.1",
|