postext 1.37.0 → 1.38.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/__tests__/comics/frames.test.d.ts +2 -0
- package/dist/__tests__/comics/frames.test.d.ts.map +1 -0
- package/dist/__tests__/comics/frames.test.js +251 -0
- package/dist/__tests__/comics/frames.test.js.map +1 -0
- package/dist/__tests__/composed/continuationRules.test.d.ts +2 -0
- package/dist/__tests__/composed/continuationRules.test.d.ts.map +1 -0
- package/dist/__tests__/composed/continuationRules.test.js +389 -0
- package/dist/__tests__/composed/continuationRules.test.js.map +1 -0
- package/dist/__tests__/composed/coverImages.test.d.ts +2 -0
- package/dist/__tests__/composed/coverImages.test.d.ts.map +1 -0
- package/dist/__tests__/composed/coverImages.test.js +75 -0
- package/dist/__tests__/composed/coverImages.test.js.map +1 -0
- package/dist/__tests__/composed/decorationSize.test.d.ts +2 -0
- package/dist/__tests__/composed/decorationSize.test.d.ts.map +1 -0
- package/dist/__tests__/composed/decorationSize.test.js +79 -0
- package/dist/__tests__/composed/decorationSize.test.js.map +1 -0
- package/dist/__tests__/composed/emptyFrames.test.d.ts +2 -0
- package/dist/__tests__/composed/emptyFrames.test.d.ts.map +1 -0
- package/dist/__tests__/composed/emptyFrames.test.js +129 -0
- package/dist/__tests__/composed/emptyFrames.test.js.map +1 -0
- package/dist/__tests__/composed/fit.test.js +10 -4
- package/dist/__tests__/composed/fit.test.js.map +1 -1
- package/dist/__tests__/composed/groups.test.js +20 -0
- package/dist/__tests__/composed/groups.test.js.map +1 -1
- package/dist/__tests__/composed/ruledFrames.test.d.ts +2 -0
- package/dist/__tests__/composed/ruledFrames.test.d.ts.map +1 -0
- package/dist/__tests__/composed/ruledFrames.test.js +93 -0
- package/dist/__tests__/composed/ruledFrames.test.js.map +1 -0
- package/dist/__tests__/composed/spread.test.js +82 -0
- package/dist/__tests__/composed/spread.test.js.map +1 -1
- package/dist/__tests__/exports.test.js +12 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/migrate/labelsOnPictures.test.d.ts +2 -0
- package/dist/__tests__/migrate/labelsOnPictures.test.d.ts.map +1 -0
- package/dist/__tests__/migrate/labelsOnPictures.test.js +114 -0
- package/dist/__tests__/migrate/labelsOnPictures.test.js.map +1 -0
- package/dist/__tests__/paragraphDropCap.test.js +38 -0
- package/dist/__tests__/paragraphDropCap.test.js.map +1 -1
- package/dist/__tests__/resourceTypePartial.test.d.ts +2 -0
- package/dist/__tests__/resourceTypePartial.test.d.ts.map +1 -0
- package/dist/__tests__/resourceTypePartial.test.js +60 -0
- package/dist/__tests__/resourceTypePartial.test.js.map +1 -0
- package/dist/canvas-backend/composed.d.ts +3 -0
- package/dist/canvas-backend/composed.d.ts.map +1 -1
- package/dist/canvas-backend/composed.js +47 -26
- package/dist/canvas-backend/composed.js.map +1 -1
- package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
- package/dist/canvas-backend/headerFooter.js +13 -0
- package/dist/canvas-backend/headerFooter.js.map +1 -1
- package/dist/canvas-backend/index.d.ts.map +1 -1
- package/dist/canvas-backend/index.js +16 -5
- package/dist/canvas-backend/index.js.map +1 -1
- package/dist/comics/frames.d.ts +82 -0
- package/dist/comics/frames.d.ts.map +1 -0
- package/dist/comics/frames.js +182 -0
- package/dist/comics/frames.js.map +1 -0
- package/dist/comics/index.d.ts +4 -1
- package/dist/comics/index.d.ts.map +1 -1
- package/dist/comics/index.js +3 -1
- package/dist/comics/index.js.map +1 -1
- package/dist/comics/layoutPage.d.ts +9 -0
- package/dist/comics/layoutPage.d.ts.map +1 -1
- package/dist/comics/layoutPage.js +53 -68
- package/dist/comics/layoutPage.js.map +1 -1
- package/dist/comics/page.d.ts.map +1 -1
- package/dist/comics/page.js +10 -1
- package/dist/comics/page.js.map +1 -1
- package/dist/comics/sourceMap.d.ts +60 -0
- package/dist/comics/sourceMap.d.ts.map +1 -0
- package/dist/comics/sourceMap.js +166 -0
- package/dist/comics/sourceMap.js.map +1 -0
- package/dist/comics/spread.d.ts.map +1 -1
- package/dist/comics/spread.js +6 -0
- package/dist/comics/spread.js.map +1 -1
- package/dist/comics/textPanels.d.ts +113 -0
- package/dist/comics/textPanels.d.ts.map +1 -0
- package/dist/comics/textPanels.js +327 -0
- package/dist/comics/textPanels.js.map +1 -0
- package/dist/comics/transform.d.ts +6 -2
- package/dist/comics/transform.d.ts.map +1 -1
- package/dist/comics/transform.js +14 -1
- package/dist/comics/transform.js.map +1 -1
- package/dist/comics/types.d.ts +10 -0
- package/dist/comics/types.d.ts.map +1 -1
- package/dist/composed/continuation.d.ts +55 -5
- package/dist/composed/continuation.d.ts.map +1 -1
- package/dist/composed/continuation.js +118 -16
- package/dist/composed/continuation.js.map +1 -1
- package/dist/composed/groups.d.ts +3 -0
- package/dist/composed/groups.d.ts.map +1 -1
- package/dist/composed/groups.js +34 -4
- package/dist/composed/groups.js.map +1 -1
- package/dist/composed/paint.d.ts +20 -1
- package/dist/composed/paint.d.ts.map +1 -1
- package/dist/composed/paint.js +40 -0
- package/dist/composed/paint.js.map +1 -1
- package/dist/composed/rules.d.ts +31 -0
- package/dist/composed/rules.d.ts.map +1 -0
- package/dist/composed/rules.js +45 -0
- package/dist/composed/rules.js.map +1 -0
- package/dist/composed/slotChecks.d.ts +2 -1
- package/dist/composed/slotChecks.d.ts.map +1 -1
- package/dist/composed/slotChecks.js +56 -2
- package/dist/composed/slotChecks.js.map +1 -1
- package/dist/composed/sourceMap.d.ts.map +1 -1
- package/dist/composed/sourceMap.js +15 -1
- package/dist/composed/sourceMap.js.map +1 -1
- package/dist/composed/spread.d.ts +20 -5
- package/dist/composed/spread.d.ts.map +1 -1
- package/dist/composed/spread.js +51 -26
- package/dist/composed/spread.js.map +1 -1
- package/dist/composed/templates.d.ts +11 -0
- package/dist/composed/templates.d.ts.map +1 -1
- package/dist/composed/templates.js +51 -2
- package/dist/composed/templates.js.map +1 -1
- package/dist/composed/types.d.ts +43 -3
- package/dist/composed/types.d.ts.map +1 -1
- package/dist/composed/validate.d.ts.map +1 -1
- package/dist/composed/validate.js +5 -3
- package/dist/composed/validate.js.map +1 -1
- package/dist/configWarnings.d.ts.map +1 -1
- package/dist/configWarnings.js +11 -1
- package/dist/configWarnings.js.map +1 -1
- package/dist/defaults/headerFooter.d.ts.map +1 -1
- package/dist/defaults/headerFooter.js +4 -0
- package/dist/defaults/headerFooter.js.map +1 -1
- package/dist/defaults/resourceTypes.d.ts +15 -0
- package/dist/defaults/resourceTypes.d.ts.map +1 -1
- package/dist/defaults/resourceTypes.js +39 -1
- package/dist/defaults/resourceTypes.js.map +1 -1
- package/dist/design/layout.d.ts +7 -0
- package/dist/design/layout.d.ts.map +1 -1
- package/dist/design/layout.js +109 -16
- package/dist/design/layout.js.map +1 -1
- package/dist/html-backend.d.ts.map +1 -1
- package/dist/html-backend.js +43 -5
- package/dist/html-backend.js.map +1 -1
- package/dist/htmlComic.d.ts +3 -0
- package/dist/htmlComic.d.ts.map +1 -1
- package/dist/htmlComic.js +2 -0
- package/dist/htmlComic.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/migrate/pageDesign.d.ts +35 -2
- package/dist/migrate/pageDesign.d.ts.map +1 -1
- package/dist/migrate/pageDesign.js +134 -7
- package/dist/migrate/pageDesign.js.map +1 -1
- package/dist/migrate/textToMarkdown.d.ts +33 -1
- package/dist/migrate/textToMarkdown.d.ts.map +1 -1
- package/dist/migrate/textToMarkdown.js +206 -9
- package/dist/migrate/textToMarkdown.js.map +1 -1
- package/dist/parse/blockParser.js +26 -0
- package/dist/parse/blockParser.js.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +219 -40
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts +5 -0
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +70 -0
- package/dist/pipeline/calloutLayout.js.map +1 -1
- package/dist/pipeline/composedLayout.d.ts.map +1 -1
- package/dist/pipeline/composedLayout.js +246 -49
- package/dist/pipeline/composedLayout.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +21 -1
- package/dist/pipeline/contentWarnings.js.map +1 -1
- package/dist/pipeline/dropCap.d.ts +5 -0
- package/dist/pipeline/dropCap.d.ts.map +1 -1
- package/dist/pipeline/dropCap.js +23 -2
- package/dist/pipeline/dropCap.js.map +1 -1
- package/dist/pipeline/frameLayout.d.ts +17 -2
- package/dist/pipeline/frameLayout.d.ts.map +1 -1
- package/dist/pipeline/frameLayout.js +47 -2
- package/dist/pipeline/frameLayout.js.map +1 -1
- package/dist/pipeline/headerFooter.d.ts.map +1 -1
- package/dist/pipeline/headerFooter.js +41 -2
- package/dist/pipeline/headerFooter.js.map +1 -1
- package/dist/pipeline/measureContentBlock.d.ts +1 -1
- package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
- package/dist/pipeline/measureContentBlock.js +4 -1
- package/dist/pipeline/measureContentBlock.js.map +1 -1
- package/dist/pipeline/resourceNumbering.d.ts.map +1 -1
- package/dist/pipeline/resourceNumbering.js +13 -4
- package/dist/pipeline/resourceNumbering.js.map +1 -1
- package/dist/preflight.js +5 -1
- package/dist/preflight.js.map +1 -1
- package/dist/types.d.ts +32 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vdt.d.ts +90 -2
- package/dist/vdt.d.ts.map +1 -1
- package/dist/vdt.js.map +1 -1
- package/package.json +1 -1
package/dist/pipeline/build.js
CHANGED
|
@@ -10,7 +10,7 @@ import { parseMarkdownMemo, spaceDirectiveLines } from '../parse';
|
|
|
10
10
|
import { buildPageLabels, computeHeadingNumbering, parseNumberFormat, } from '../numbering';
|
|
11
11
|
import { extractFrontmatter, normalizeMetadata } from '../frontmatter';
|
|
12
12
|
import { collectConfigWarnings } from '../configWarnings';
|
|
13
|
-
import { initHyphenator } from '../measure';
|
|
13
|
+
import { initHyphenator, measureRichBlock } from '../measure';
|
|
14
14
|
import { setHyphenationRules } from '../hyphenate';
|
|
15
15
|
import { citedNames } from '../citations/names';
|
|
16
16
|
import { getCjkLineBreak, setCjkLineBreak } from '../measure/cjkClasses';
|
|
@@ -38,9 +38,9 @@ import { applyStatementNumbering, numberStatements, outlineLookup } from './stat
|
|
|
38
38
|
import { SPAN_EMBED_STYLE_ID, isPageSpanStrip, spanEmbedStyle, wrapPageSpanEmbeds } from './spanEmbeds';
|
|
39
39
|
import { flowColumnsStyles, isFlowColumnsStyle, wrapFlowColumns } from './flowColumns';
|
|
40
40
|
import { FRAME_STYLE_ID, frameBoxStyle, wrapComposedPages } from '../composed/wrap';
|
|
41
|
-
import { resolvePageTemplate } from '../composed/templates';
|
|
41
|
+
import { continueInPage, resolvePageTemplate } from '../composed/templates';
|
|
42
42
|
import { layoutComposedSpread } from '../composed/spread';
|
|
43
|
-
import { assignReceivers, continuationTarget, MAX_CONTINUATION_PAGES } from '../composed/continuation';
|
|
43
|
+
import { assignJumpReceivers, assignReceivers, continuationTarget, MAX_CONTINUATION_PAGES } from '../composed/continuation';
|
|
44
44
|
import { frameElementId } from '../composed/ids';
|
|
45
45
|
import { nextFrameOf } from '../composed/geometry';
|
|
46
46
|
import { composedPageAt, frameStyleOf, layoutComposedPage, planComposedPages } from './composedLayout';
|
|
@@ -55,6 +55,7 @@ import { chooseParagraphSplit } from './orphanWidow';
|
|
|
55
55
|
import { layoutComicPage, comicPageLayoutWarnings } from '../comics/layoutPage';
|
|
56
56
|
import { comicStripExtent, comicStripOffset, comicStripPlacement, comicStripWidth, layoutComicStrip } from '../comics/strip';
|
|
57
57
|
import { isComicSpread, layoutComicSpread } from '../comics/spread';
|
|
58
|
+
import { comicTextPanelsSupported, layoutComicTextFrames, planComicTextPanels, wrapComicTextPanels } from '../comics/textPanels';
|
|
58
59
|
import { applyStyleAttrs, computePageMetrics, flowPageMirrored, pageMirrored, sheetRectToFlow, isMarkerBlock, nextNonMarkerBlock, spaceLinesAfter, prevNonMarkerBlock, rollbackTrailingBlocks, } from './buildHelpers';
|
|
59
60
|
import { measureContentBlock } from './measureContentBlock';
|
|
60
61
|
import { containerStyle, paragraphStyleIdOf, planParagraphContainers } from './paragraphContainers';
|
|
@@ -499,7 +500,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
499
500
|
// in a frame is a group of its box.
|
|
500
501
|
const templateSource = { pageTemplates: resolved.pageTemplates, calloutStyles: resolved.calloutStyles };
|
|
501
502
|
const composedWrap = wrapComposedPages(numberedBlocks, templateSource);
|
|
502
|
-
|
|
503
|
+
// A comic page's text panels (#885): each panel's Markdown in a story
|
|
504
|
+
// box of the same kind, set in the panel's frame (below).
|
|
505
|
+
const comicText = wrapComicTextPanels(composedWrap.blocks, comicTextPanelsSupported(resolved));
|
|
506
|
+
const flowGroups = resolved.layout.flowColumns ? wrapFlowColumns(comicText.blocks) : { blocks: comicText.blocks, wrapped: false };
|
|
503
507
|
const spanEmbeds = wrapPageSpanEmbeds(flowGroups.blocks, content.resources ?? [], effectiveResourceTypes(config, content.resources ?? []));
|
|
504
508
|
// Code listings (#624): each in a box of the code style, which the
|
|
505
509
|
// callout machinery places and splits.
|
|
@@ -554,7 +558,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
554
558
|
...(spanEmbeds.wrapped ? [spanEmbedStyle(bodyStyle.lineHeightPx, resolved.layout.inlineResourceGap !== 'above')] : []),
|
|
555
559
|
...(codeBoxes.wrapped ? [codeBoxStyle(resolved)] : []),
|
|
556
560
|
// The frameless box of a composed page's story (#855).
|
|
557
|
-
...(composedWrap.wrapped ? [frameBoxStyle(Math.max(resolved.bodyText.avoidOrphans ? resolved.bodyText.orphanMinLines : 1, resolved.bodyText.avoidWidows ? resolved.bodyText.widowMinLines : 1))] : []),
|
|
561
|
+
...(composedWrap.wrapped || comicText.wrapped ? [frameBoxStyle(Math.max(resolved.bodyText.avoidOrphans ? resolved.bodyText.orphanMinLines : 1, resolved.bodyText.avoidWidows ? resolved.bodyText.widowMinLines : 1))] : []),
|
|
558
562
|
// The boxes of main-flow groups: sub-columns a body line apart in the
|
|
559
563
|
// text column, a gutter apart across the page.
|
|
560
564
|
...(flowGroups.wrapped
|
|
@@ -566,7 +570,7 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
566
570
|
: resolved.calloutStyles;
|
|
567
571
|
// A box nested in another looks its style up in the configuration it is
|
|
568
572
|
// laid out with: the listings' box among them.
|
|
569
|
-
const calloutResolved = codeBoxes.wrapped || flowGroups.wrapped || composedWrap.wrapped ? { ...resolved, calloutStyles } : resolved;
|
|
573
|
+
const calloutResolved = codeBoxes.wrapped || flowGroups.wrapped || composedWrap.wrapped || comicText.wrapped ? { ...resolved, calloutStyles } : resolved;
|
|
570
574
|
const blockquoteStyle = resolveBlockquoteStyle(resolved);
|
|
571
575
|
const listLevelIndentsPx = computeLevelIndentsPx(resolved, bodyStyle.fontSizePx);
|
|
572
576
|
const orderedMetrics = computeOrderedListRunMetrics(contentBlocks, resolved, bodyStyle.fontSizePx);
|
|
@@ -602,10 +606,12 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
602
606
|
// story holds does not float. A reference in a frame to a picture set
|
|
603
607
|
// elsewhere floats from the page's end, to the pages after it.
|
|
604
608
|
const composedPlans = planComposedPages(contentBlocks, calloutPlan, templateSource);
|
|
605
|
-
|
|
609
|
+
// A comic page's text panels (#885) likewise.
|
|
610
|
+
const comicTextPlans = comicText.wrapped ? planComicTextPanels(contentBlocks, calloutPlan) : new Map();
|
|
611
|
+
if (composedPlans.size > 0 || comicTextPlans.size > 0) {
|
|
606
612
|
for (let k = floatPlan.length - 1; k >= 0; k--) {
|
|
607
613
|
const f = floatPlan[k];
|
|
608
|
-
const page = composedPageAt(composedPlans, f.firstBlockIdx);
|
|
614
|
+
const page = composedPageAt(composedPlans, f.firstBlockIdx) ?? composedPageAt(comicTextPlans, f.firstBlockIdx);
|
|
609
615
|
if (!page)
|
|
610
616
|
continue;
|
|
611
617
|
const raw = contentBlocks[f.firstBlockIdx];
|
|
@@ -5955,6 +5961,19 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
5955
5961
|
return false;
|
|
5956
5962
|
},
|
|
5957
5963
|
};
|
|
5964
|
+
/** Every frame of the composed pages laid so far, by id: a story that
|
|
5965
|
+
* jumps to a later page (#917) links its pieces across pages. */
|
|
5966
|
+
const frameAt = new Map();
|
|
5967
|
+
/** The planned composed pages by their fence's `id` (#917): where a
|
|
5968
|
+
* `'page:<id>'` continuation lands. */
|
|
5969
|
+
const fenceById = new Map();
|
|
5970
|
+
for (const pl of composedPlans.values()) {
|
|
5971
|
+
const id = contentBlocks[pl.startIdx]?.composedPage?.attrs.id;
|
|
5972
|
+
if (id !== undefined && id !== '' && !fenceById.has(id))
|
|
5973
|
+
fenceById.set(id, pl);
|
|
5974
|
+
}
|
|
5975
|
+
/** Stories waiting for the later page fence they jump to, by its id. */
|
|
5976
|
+
const jumps = new Map();
|
|
5958
5977
|
/** Set the composed page `planned` on a fresh page (#855), or a spread
|
|
5959
5978
|
* template on the two facing pages from the next verso (#861). */
|
|
5960
5979
|
const placeComposedPage = (planned, fence) => {
|
|
@@ -6005,11 +6024,15 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6005
6024
|
recto.columns = [createVDTColumn(0, recto.contentArea)];
|
|
6006
6025
|
cursor.columnIndex = 0;
|
|
6007
6026
|
// The sheet is laid in the pages' flow: the left page first, or the
|
|
6008
|
-
// right one where the flow is mirrored (right to left)
|
|
6027
|
+
// right one where the flow is mirrored (right to left) or turned (a
|
|
6028
|
+
// vertical page, #926: the flow's y runs from the sheet's right edge
|
|
6029
|
+
// to its left, and the right page comes first along it).
|
|
6009
6030
|
const versoIsLeft = resolved.page.binding !== 'right';
|
|
6010
|
-
const
|
|
6031
|
+
const vertical = pageIsVertical(verso);
|
|
6032
|
+
const flowMirrored = pageIsMirrored(verso) || vertical;
|
|
6011
6033
|
const left = versoIsLeft ? verso : recto;
|
|
6012
6034
|
const right = versoIsLeft ? recto : verso;
|
|
6035
|
+
const frames = designFramesOn(verso);
|
|
6013
6036
|
const out = layoutComposedSpread({
|
|
6014
6037
|
...common(flowMirrored ? right : left, { id: sheet.id, spread: true }),
|
|
6015
6038
|
...extra,
|
|
@@ -6017,8 +6040,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6017
6040
|
first: flowMirrored ? right : left,
|
|
6018
6041
|
second: flowMirrored ? left : right,
|
|
6019
6042
|
firstSide: flowMirrored ? 'right' : 'left',
|
|
6020
|
-
trim:
|
|
6021
|
-
bleed:
|
|
6043
|
+
trim: frames.page,
|
|
6044
|
+
bleed: frames.bleed,
|
|
6045
|
+
...(vertical ? { axis: 'y' } : {}),
|
|
6022
6046
|
});
|
|
6023
6047
|
return { sides: out.sides, warnings: out.warnings, laid: out.laid, continuations: out.continuations };
|
|
6024
6048
|
};
|
|
@@ -6034,9 +6058,43 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6034
6058
|
return { parity, template, areas: { area, page: frames.page, bleed: frames.bleed } };
|
|
6035
6059
|
};
|
|
6036
6060
|
let continuations;
|
|
6061
|
+
// Stories that jump to this page (#917): they go on in the frames its
|
|
6062
|
+
// own content leaves empty; those that find none go on after it.
|
|
6063
|
+
const incoming = fence.attrs.id !== undefined ? jumps.get(fence.attrs.id) ?? [] : [];
|
|
6064
|
+
if (fence.attrs.id !== undefined)
|
|
6065
|
+
jumps.delete(fence.attrs.id);
|
|
6066
|
+
let jumpReceivers = new Map();
|
|
6067
|
+
let jumpLeft = [];
|
|
6068
|
+
const receive = (template) => {
|
|
6069
|
+
if (incoming.length === 0)
|
|
6070
|
+
return {};
|
|
6071
|
+
const names = new Set(template.frames.map((f) => f.name));
|
|
6072
|
+
const prev = new Map();
|
|
6073
|
+
for (const f of template.frames) {
|
|
6074
|
+
const n = nextFrameOf(f);
|
|
6075
|
+
if (n && names.has(n) && !prev.has(n))
|
|
6076
|
+
prev.set(n, f.name);
|
|
6077
|
+
}
|
|
6078
|
+
const headOf = (n) => {
|
|
6079
|
+
const seen = new Set([n]);
|
|
6080
|
+
let at = n;
|
|
6081
|
+
for (let q = prev.get(at); q !== undefined && !seen.has(q); q = prev.get(at)) {
|
|
6082
|
+
seen.add(q);
|
|
6083
|
+
at = q;
|
|
6084
|
+
}
|
|
6085
|
+
return at;
|
|
6086
|
+
};
|
|
6087
|
+
const assigned = assignJumpReceivers(template, incoming, (n) => planned.stories.has(headOf(n)));
|
|
6088
|
+
jumpReceivers = assigned.receivers;
|
|
6089
|
+
jumpLeft = assigned.left;
|
|
6090
|
+
return {
|
|
6091
|
+
stories: new Map([...planned.stories, ...[...jumpReceivers].map(([n, c]) => [n, c.story])]),
|
|
6092
|
+
continuing: { receivers: jumpReceivers, generation: 0, collapse: false, last: false, jump: true },
|
|
6093
|
+
};
|
|
6094
|
+
};
|
|
6037
6095
|
const sheet = resolvePageTemplate(templateSource, fence.template, { spread: true });
|
|
6038
6096
|
if (sheet?.spread) {
|
|
6039
|
-
const out = laySpread(sheet,
|
|
6097
|
+
const out = laySpread(sheet, receive(sheet));
|
|
6040
6098
|
placed.push(...out.sides);
|
|
6041
6099
|
composedNotes.push(...out.warnings);
|
|
6042
6100
|
laid = out.laid;
|
|
@@ -6045,19 +6103,20 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6045
6103
|
else {
|
|
6046
6104
|
const page = doc.pages[cursor.pageIndex];
|
|
6047
6105
|
const { parity, template, areas } = singleOn(page, fence.template);
|
|
6106
|
+
const extra = receive(template);
|
|
6048
6107
|
// Kept by what it reads (#857): a page met again is not set again.
|
|
6049
|
-
// A spread is laid out afresh each time (its two sides are one sheet)
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
template,
|
|
6054
|
-
areas,
|
|
6055
|
-
}, composedMemo);
|
|
6108
|
+
// A spread is laid out afresh each time (its two sides are one sheet),
|
|
6109
|
+
// and so is a page a story jumps to.
|
|
6110
|
+
const args = { ...common(page, { id: template.id, spread: false, parity }), page, template, areas };
|
|
6111
|
+
const out = extra.continuing ? layoutComposedPage({ ...args, ...extra }) : layoutComposedPageMemo(args, composedMemo);
|
|
6056
6112
|
placed.push({ page, composed: out.composed, blocks: out.blocks });
|
|
6057
6113
|
composedNotes.push(...out.warnings);
|
|
6058
6114
|
laid = out.laid;
|
|
6059
6115
|
continuations = out.continuations;
|
|
6060
6116
|
}
|
|
6117
|
+
// A jumping story that found no free frame here goes on after it.
|
|
6118
|
+
if (jumpLeft.length > 0)
|
|
6119
|
+
continuations = [...(continuations ?? []), ...jumpLeft.map((c) => ({ ...c, rule: 'next-page', template: placed[0].composed.template, collapsed: false }))];
|
|
6061
6120
|
const commit = (list) => {
|
|
6062
6121
|
for (const { page, composed, blocks } of list) {
|
|
6063
6122
|
page.composed = composed;
|
|
@@ -6073,7 +6132,6 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6073
6132
|
// (or spread) per template it goes on to, generation after generation,
|
|
6074
6133
|
// each laid afresh after the pages before it. The added pages are
|
|
6075
6134
|
// ordinary pages (numbered, with running heads, sides kept).
|
|
6076
|
-
const frameAt = new Map();
|
|
6077
6135
|
const indexFrames = (list) => {
|
|
6078
6136
|
for (const s of list)
|
|
6079
6137
|
for (const f of s.composed.frames)
|
|
@@ -6081,9 +6139,63 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6081
6139
|
frameAt.set(f.id, { page: s.page, frame: f });
|
|
6082
6140
|
};
|
|
6083
6141
|
indexFrames(placed);
|
|
6142
|
+
/** The sending frame of `c` points to the frame `to` that took it, and
|
|
6143
|
+
* its page's log says where it went. */
|
|
6144
|
+
const link = (c, to) => {
|
|
6145
|
+
const src = frameAt.get(c.fromFrameId);
|
|
6146
|
+
const dst = frameAt.get(to);
|
|
6147
|
+
if (!src || !dst)
|
|
6148
|
+
return;
|
|
6149
|
+
src.frame.continuesTo = to;
|
|
6150
|
+
const log = src.page.composed.log;
|
|
6151
|
+
let at = log.length;
|
|
6152
|
+
for (let i = log.length - 1; i >= 0; i--) {
|
|
6153
|
+
if (log[i].frame === c.frame) {
|
|
6154
|
+
at = i + 1;
|
|
6155
|
+
break;
|
|
6156
|
+
}
|
|
6157
|
+
}
|
|
6158
|
+
log.splice(at, 0, { frame: c.frame, kind: 'continued', toPage: dst.page.index, toFrame: to });
|
|
6159
|
+
};
|
|
6160
|
+
for (const [name, c] of jumpReceivers)
|
|
6161
|
+
link(c, frameElementId(fence.fenceIndex, name));
|
|
6162
|
+
/** Stories that jump to a later page fence (#917) wait for it; one
|
|
6163
|
+
* whose fence is not after this page goes on on the next page, and
|
|
6164
|
+
* says so. */
|
|
6165
|
+
const route = (list) => {
|
|
6166
|
+
const out = [];
|
|
6167
|
+
for (const c of list) {
|
|
6168
|
+
const target = continueInPage(c.rule);
|
|
6169
|
+
if (!target) {
|
|
6170
|
+
out.push(c);
|
|
6171
|
+
continue;
|
|
6172
|
+
}
|
|
6173
|
+
const to = fenceById.get(target.page);
|
|
6174
|
+
if (to && to.startIdx > planned.endIdx) {
|
|
6175
|
+
const waiting = jumps.get(target.page) ?? [];
|
|
6176
|
+
waiting.push(c);
|
|
6177
|
+
jumps.set(target.page, waiting);
|
|
6178
|
+
continue;
|
|
6179
|
+
}
|
|
6180
|
+
const from = frameAt.get(c.fromFrameId);
|
|
6181
|
+
composedNotes.push({
|
|
6182
|
+
kind: 'continueTargetMissing',
|
|
6183
|
+
template: c.template,
|
|
6184
|
+
frame: c.frame,
|
|
6185
|
+
fenceIndex: fence.fenceIndex,
|
|
6186
|
+
target: target.page,
|
|
6187
|
+
configPath: resolvePageTemplate(templateSource, c.template)?.frames.find((f) => f.name === c.frame)?.configPath ?? '',
|
|
6188
|
+
...(to ? { before: true } : {}),
|
|
6189
|
+
...(from?.frame.sourceStart !== undefined ? { sourceStart: from.frame.sourceStart, sourceEnd: from.frame.sourceEnd } : {}),
|
|
6190
|
+
...(from ? { pageIndex: from.page.index } : {}),
|
|
6191
|
+
});
|
|
6192
|
+
out.push({ ...c, rule: 'next-page' });
|
|
6193
|
+
}
|
|
6194
|
+
return out;
|
|
6195
|
+
};
|
|
6084
6196
|
const overflowTemplateOf = (id) => resolvePageTemplate(templateSource, id)?.overflowTemplate;
|
|
6085
6197
|
const firstPage = placed[0]?.page.index ?? cursor.pageIndex;
|
|
6086
|
-
let pending = continuations ?? [];
|
|
6198
|
+
let pending = route(continuations ?? []);
|
|
6087
6199
|
for (let generation = 1; pending.length > 0; generation++) {
|
|
6088
6200
|
const last = generation >= MAX_CONTINUATION_PAGES;
|
|
6089
6201
|
let queue = pending;
|
|
@@ -6164,25 +6276,10 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6164
6276
|
composedNotes.push(...notes);
|
|
6165
6277
|
// Each frame that sent content on points to the frame that took it,
|
|
6166
6278
|
// and its page's log says where it went.
|
|
6167
|
-
for (const c of receivers.values())
|
|
6168
|
-
|
|
6169
|
-
const src = frameAt.get(c.fromFrameId);
|
|
6170
|
-
const dst = frameAt.get(to);
|
|
6171
|
-
if (!src || !dst)
|
|
6172
|
-
continue;
|
|
6173
|
-
src.frame.continuesTo = to;
|
|
6174
|
-
const log = src.page.composed.log;
|
|
6175
|
-
let at = log.length;
|
|
6176
|
-
for (let i = log.length - 1; i >= 0; i--) {
|
|
6177
|
-
if (log[i].frame === c.frame) {
|
|
6178
|
-
at = i + 1;
|
|
6179
|
-
break;
|
|
6180
|
-
}
|
|
6181
|
-
}
|
|
6182
|
-
log.splice(at, 0, { frame: c.frame, kind: 'continued', toPage: dst.page.index, toFrame: to });
|
|
6183
|
-
}
|
|
6279
|
+
for (const c of receivers.values())
|
|
6280
|
+
link(c, frameElementId(fence.fenceIndex, c.slot, generation));
|
|
6184
6281
|
if (more)
|
|
6185
|
-
pending.push(...more);
|
|
6282
|
+
pending.push(...route(more));
|
|
6186
6283
|
}
|
|
6187
6284
|
}
|
|
6188
6285
|
for (const [head, story] of planned.stories) {
|
|
@@ -6194,6 +6291,39 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6194
6291
|
pendingComposedBreak = 'page';
|
|
6195
6292
|
flushPendingNumberingAtBoundary();
|
|
6196
6293
|
};
|
|
6294
|
+
/**
|
|
6295
|
+
* The text panels of a comic page (#885): each story set in its panel's
|
|
6296
|
+
* frame (`layoutComicTextFrames`), its blocks floats of the page; the
|
|
6297
|
+
* stories laid are done for the main loop.
|
|
6298
|
+
*/
|
|
6299
|
+
const placeComicText = (page, comic, plan) => {
|
|
6300
|
+
const frameless = calloutStyles.find((st) => st.id === FRAME_STYLE_ID);
|
|
6301
|
+
const out = layoutComicTextFrames({
|
|
6302
|
+
pass: framePass,
|
|
6303
|
+
resolved,
|
|
6304
|
+
page,
|
|
6305
|
+
comic,
|
|
6306
|
+
plan,
|
|
6307
|
+
styleOf: (frame) => frameStyleOf((frame.style ? resolved.calloutStyles.find((st) => st.id === frame.style) : undefined) ?? frameless, frame),
|
|
6308
|
+
dpi,
|
|
6309
|
+
emPx: bodyStyle.fontSizePx,
|
|
6310
|
+
bodyOffset,
|
|
6311
|
+
mirrored: mirroredOf(page),
|
|
6312
|
+
pushGapPx: wrapGapPx(resolved.layout.wrap?.gap, dpi, bodyStyle.fontSizePx, floatGapPx),
|
|
6313
|
+
locale: resolvedLocale(resolved),
|
|
6314
|
+
});
|
|
6315
|
+
const floats = (page.floats ??= []);
|
|
6316
|
+
for (const b of out.blocks) {
|
|
6317
|
+
floats.push(b);
|
|
6318
|
+
doc.blocks.push(b);
|
|
6319
|
+
}
|
|
6320
|
+
for (const [key, story] of plan.stories) {
|
|
6321
|
+
if (!out.laid.has(key))
|
|
6322
|
+
continue;
|
|
6323
|
+
for (let i = story.startIdx; i <= story.plan.endIdx; i++)
|
|
6324
|
+
composedLaid.add(i);
|
|
6325
|
+
}
|
|
6326
|
+
};
|
|
6197
6327
|
/** The first block of the document that sets something: a heading there
|
|
6198
6328
|
* opens the document's first page (`openerPages`, #749). */
|
|
6199
6329
|
const firstFlowBlockIdx = contentBlocks.findIndex((b) => !isMarkerBlock(b) && b.type !== 'directive');
|
|
@@ -6478,6 +6608,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
6478
6608
|
sourceOffset: bodyOffset,
|
|
6479
6609
|
mirrorMargins: pageMirrored(resolved, page.index, pageIndexOffset, true),
|
|
6480
6610
|
});
|
|
6611
|
+
const textPlan = comicTextPlans.get(blockIdx);
|
|
6612
|
+
if (textPlan)
|
|
6613
|
+
placeComicText(page, page.comic, textPlan);
|
|
6481
6614
|
}
|
|
6482
6615
|
pendingComicBreak = true;
|
|
6483
6616
|
flushPendingNumberingAtBoundary();
|
|
@@ -8434,6 +8567,9 @@ function placeDocumentPass(content, config, cache, options, hints) {
|
|
|
8434
8567
|
page.pageLabel = info.label;
|
|
8435
8568
|
page.pageNumberFormat = info.format;
|
|
8436
8569
|
}
|
|
8570
|
+
// Continuation marks with a page number (#917): the page the rest goes
|
|
8571
|
+
// on on, or comes from, now that pages are numbered.
|
|
8572
|
+
fillPageMarks(doc.pages);
|
|
8437
8573
|
const restarts = pageNumberSegments
|
|
8438
8574
|
.filter((s, i) => i > 0 && s.startAt !== undefined && s.startPageIndex < doc.pages.length)
|
|
8439
8575
|
.map((s) => s.startPageIndex);
|
|
@@ -8662,6 +8798,49 @@ function afterTextWarnings(doc) {
|
|
|
8662
8798
|
}
|
|
8663
8799
|
return out;
|
|
8664
8800
|
}
|
|
8801
|
+
/**
|
|
8802
|
+
* Write the page numbers into the continuation marks of composed pages'
|
|
8803
|
+
* frames (#917, `VDTDesignTextBlock.pageMark`): `{page}` becomes the label
|
|
8804
|
+
* of the page the frame's rest goes on on (`continuesTo`) or comes from
|
|
8805
|
+
* (`continuedFrom`). The mark was laid out with a guess of the number; its
|
|
8806
|
+
* lines are measured again with the true one and keep their alignment.
|
|
8807
|
+
*/
|
|
8808
|
+
function fillPageMarks(pages) {
|
|
8809
|
+
const frames = new Map();
|
|
8810
|
+
for (const p of pages)
|
|
8811
|
+
for (const f of p.composed?.frames ?? [])
|
|
8812
|
+
if (!f.facingBlocks)
|
|
8813
|
+
frames.set(f.id, p);
|
|
8814
|
+
for (const p of pages) {
|
|
8815
|
+
for (const f of p.composed?.frames ?? []) {
|
|
8816
|
+
for (const id of f.blockIds) {
|
|
8817
|
+
const box = p.floats?.find((b) => b.id === id);
|
|
8818
|
+
for (const d of box?.designOverlay?.blocks ?? []) {
|
|
8819
|
+
if (d.kind !== 'text' || !d.pageMark)
|
|
8820
|
+
continue;
|
|
8821
|
+
const other = d.pageMark.page === 'to' ? f.continuesTo : f.continuedFrom;
|
|
8822
|
+
const at = other !== undefined ? frames.get(other) : undefined;
|
|
8823
|
+
if (!at)
|
|
8824
|
+
continue;
|
|
8825
|
+
const label = at.pageLabel ?? String(at.pageNumberValue ?? at.index + 1);
|
|
8826
|
+
const text = d.pageMark.text.split('{page}').join(label);
|
|
8827
|
+
const lh = d.lines.length > 0 ? d.bbox.height / d.lines.length : d.bbox.height;
|
|
8828
|
+
const first = d.lines[0];
|
|
8829
|
+
const slack0 = first ? d.bbox.width - first.width : 0;
|
|
8830
|
+
const align = !first || first.xOffset < 0.5 ? 'left' : Math.abs(first.xOffset - slack0) < 0.5 ? 'right' : 'center';
|
|
8831
|
+
const base = first ? first.baselineY - d.bbox.y : lh * 0.8;
|
|
8832
|
+
const { lines } = measureRichBlock([{ text, bold: false, italic: false }], d.fontString, d.fontString, d.fontString, d.fontString, d.bbox.width, lh, { textAlign: 'left' });
|
|
8833
|
+
if (lines.length === 0)
|
|
8834
|
+
continue;
|
|
8835
|
+
d.lines = lines.map((ln, i) => {
|
|
8836
|
+
const slack = Math.max(0, d.bbox.width - ln.bbox.width);
|
|
8837
|
+
return { text: ln.text, xOffset: align === 'right' ? slack : align === 'center' ? slack / 2 : 0, baselineY: d.bbox.y + base + i * lh, width: ln.bbox.width };
|
|
8838
|
+
});
|
|
8839
|
+
}
|
|
8840
|
+
}
|
|
8841
|
+
}
|
|
8842
|
+
}
|
|
8843
|
+
}
|
|
8665
8844
|
/** `doc` with the page of each of its index marks (`doc.indexMarks`). */
|
|
8666
8845
|
function withIndexMarks(doc, content) {
|
|
8667
8846
|
const { content: body, contentOffset } = extractFrontmatter(content.markdown);
|