Moments across up to four pages: stacked in Flow, side by side in Page/Book (BL-0055)
The save sheet gets "+ Previous page" / "+ Next page" (right to left for rtl in Page/Book) for a picture that runs over several pages. Moments store a layout (row | column); pages the selected region does not touch are dropped. Crops, viewer and gallery draw both layouts. Dialogs now clean up directly instead of waiting for the "close" event, which a backgrounded page can deliver late (a closed sheet stayed in the page and M stopped working). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
74842c59e0
commit
5497e8bfbc
9 files changed
+175
-92
No files matched your search
+23
-6
@@ -5,7 +5,7 @@ const fs = require('fs'), os = require('os'), path = require('path'), net = requ
|
||||
const { spawn } = require('child_process');
|
||||
const { Canvas } = require('../tools/png');
|
||||
const moments = require('../moments');
|
||||
const { narrowToPage } = require('../public/moments');
|
||||
const { trimPages, momentPageLabel } = require('../public/moments');
|
||||
const { READER_KEYS, MOMENT_VIEWER_KEYS, keyAction } = require('../public/keys');
|
||||
|
||||
test('regions are clamped fractions; a whole-page rectangle means no region', () => {
|
||||
@@ -25,13 +25,23 @@ test('exactly one known category is required; notes are trimmed and capped', ()
|
||||
assert.equal(moments.cleanNote('x'.repeat(500)).length, moments.NOTE_MAX);
|
||||
});
|
||||
|
||||
test('a spread region inside one page becomes that page alone', () => {
|
||||
const near = (a, b) => Math.abs(a - b) < 1e-9;
|
||||
test('side by side: a region inside one page of a spread becomes that page alone', () => {
|
||||
const left = { i: 5, w: 700, h: 1000 }, right = { i: 4, w: 700, h: 1000 };
|
||||
const one = narrowToPage([left, right], { x: 0.6, y: 0.1, w: 0.2, h: 0.3 });
|
||||
const one = trimPages([left, right], { x: 0.6, y: 0.1, w: 0.2, h: 0.3 });
|
||||
assert.deepEqual(one.pages, [right]);
|
||||
assert.ok(Math.abs(one.region.x - 0.2) < 1e-9 && Math.abs(one.region.w - 0.4) < 1e-9);
|
||||
const both = narrowToPage([left, right], { x: 0.3, y: 0.1, w: 0.4, h: 0.3 });
|
||||
assert.equal(both.pages.length, 2);
|
||||
assert.ok(near(one.region.x, 0.2) && near(one.region.w, 0.4) && one.region.y === 0.1);
|
||||
assert.equal(trimPages([left, right], { x: 0.3, y: 0.1, w: 0.4, h: 0.3 }).pages.length, 2);
|
||||
});
|
||||
|
||||
test('stacked (Flow): a picture across the break keeps only the pages it touches', () => {
|
||||
const pages = [0, 1, 2, 3].map(i => ({ i, w: 800, h: 400 })); // each page is half as tall as wide: 0.5 of the width
|
||||
// The stack is 2 units tall; y 0.4–0.6 is the lower half of page 1 and the upper half of page 2.
|
||||
const cut = trimPages(pages, { x: 0.1, y: 0.4, w: 0.8, h: 0.2 }, 'column');
|
||||
assert.deepEqual(cut.pages.map(p => p.i), [1, 2]);
|
||||
assert.ok(near(cut.region.y, 0.3) && near(cut.region.h, 0.4) && cut.region.x === 0.1);
|
||||
assert.deepEqual(trimPages(pages, null, 'column').pages.length, 4);
|
||||
assert.equal(momentPageLabel(cut.pages), 'p. 2–3');
|
||||
});
|
||||
|
||||
test('every reader key is bound once and the M / I split holds', () => {
|
||||
@@ -99,6 +109,13 @@ test('moments are private, validated, editable and survive page renumbering as "
|
||||
assert.match(created.moment.pages[0].u, /^lib\/Moon%20Garden\/v01\/c001%20Roots\/002\.png$/);
|
||||
const spread = (await (await post(alice, '/api/moments', { ...base3, pages: [2, 0], cat: 'twist' })).json()).moment;
|
||||
assert.deepEqual(spread.pages.map(p => p.i), [2, 0]);
|
||||
assert.equal(spread.layout, 'row');
|
||||
// Flow: a picture stacked over three pages; more than four pages or an unknown layout is refused.
|
||||
const stacked = (await (await post(alice, '/api/moments', { ...base3, pages: [0, 1, 2], layout: 'column', cat: 'awesome', region: { x: 0, y: 0.2, w: 1, h: 0.5 } })).json()).moment;
|
||||
assert.equal(stacked.layout, 'column');
|
||||
assert.equal((await post(alice, '/api/moments', { ...base3, pages: [0, 1, 2, 0], cat: 'hot' })).status, 400);
|
||||
assert.equal((await post(alice, '/api/moments', { ...base3, pages: [0], layout: 'grid', cat: 'hot' })).status, 400);
|
||||
assert.equal((await post(alice, '/api/moments/delete', { id: stacked.id })).status, 200);
|
||||
|
||||
// Story order: page 0/2 spread starts before page 1.
|
||||
const listed = (await get(alice, '/api/moments?m=Moon%20Garden')).moments;
|
||||
|
||||
Reference in new issue
Block a user