Expand replaces Widen: fill the window in both directions
From the development repository at 3f1da52. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
51e66db9a1
commit
cc0b8dbd31
9 files changed
+101
-71
No files matched your search
+2
-2
@@ -78,8 +78,8 @@
|
||||
data-help="Show the whole page in the window. Pressed by the host, it does so on every screen. Ctrl (Command on a Mac) with the scroll wheel, or with a pen stroke up or down, zooms about the pointer.">Fit</button>
|
||||
<button id="zoom_sheet" type="button"
|
||||
data-help="Show the page at the scale a new page has: one A4 sheet filling the window. A shrunk page is then seen at its size on the sheet. Pressed by the host, it does so on every screen.">A4</button>
|
||||
<button id="zoom_widen" type="button" hidden
|
||||
data-help="Make the page wider, for everyone, until it fills the window at this zoom. Nothing on it moves.">Widen</button>
|
||||
<button id="zoom_expand" type="button" hidden
|
||||
data-help="Make the page fill the window, for everyone, at this zoom, in both directions. Nothing on it moves.">Expand</button>
|
||||
<button id="zoom_shrink" type="button" hidden
|
||||
data-help="Make the page, for everyone, just large enough for what is on it, with the margin around. Nothing on it moves.">Shrink</button>
|
||||
<label class="toggle" data-help="Let the page grow when your writing reaches an edge. Off, your writing stops at the edge. Images always get the room they need.">
|
||||
|
||||
+12
-8
@@ -1027,12 +1027,16 @@ async function enterSession(invitationText, name, notebook) {
|
||||
renderer.sheetScale();
|
||||
session.sendViewCommand('sheet');
|
||||
});
|
||||
// "Widen" makes the sheet itself wider, until it fills the window at
|
||||
// the present zoom; nothing on it moves (Andy, 2026-10-08).
|
||||
element('zoom_widen').addEventListener('click', () => {
|
||||
const room = renderer.available().width / renderer.cssPixelsPerUnit;
|
||||
const widened = session.widenPage(room);
|
||||
if (widened) log(`Page widened to ${session.page.baseWidth / 100} cm`);
|
||||
// "Expand" makes the sheet itself fill the window at the present zoom,
|
||||
// in both directions; nothing on it moves (Andy, 2026-10-08 for the
|
||||
// width, both ways 2026-10-11).
|
||||
element('zoom_expand').addEventListener('click', () => {
|
||||
const room = renderer.available();
|
||||
const expanded = session.expandPage(room.width / renderer.cssPixelsPerUnit,
|
||||
room.height / renderer.cssPixelsPerUnit);
|
||||
if (expanded) {
|
||||
log(`Page expanded to ${session.page.baseWidth / 100} by ${session.page.baseHeight / 100} cm`);
|
||||
}
|
||||
});
|
||||
element('zoom_shrink').addEventListener('click', () => {
|
||||
if (session.shrinkPage()) {
|
||||
@@ -1062,7 +1066,7 @@ async function enterSession(invitationText, name, notebook) {
|
||||
const hideTool = /** @type {HTMLElement} */ (document.querySelector('[data-tool=hide]'));
|
||||
hideTool.hidden = !session.mayMakePages();
|
||||
if (hideTool.hidden && tool === 'hide') /** @type {HTMLElement} */ (document.querySelector('[data-tool=pen]')).click();
|
||||
element('zoom_widen').hidden = !session.mayMakePages();
|
||||
element('zoom_expand').hidden = !session.mayMakePages();
|
||||
element('zoom_shrink').hidden = !session.mayMakePages();
|
||||
}
|
||||
showHostTools();
|
||||
@@ -1413,7 +1417,7 @@ function showParticipants(session, renderer) {
|
||||
// A checkbox with its label to the left, like Extend (Andy, 2026-10-09).
|
||||
const allowLine = document.createElement('label');
|
||||
allowLine.className = 'allow_line';
|
||||
allowLine.setAttribute('data-help', 'Make this participant a co-host: they may then start pages, put images on the page and arrange them, load notebook pages, widen, shrink and hide, as you can.');
|
||||
allowLine.setAttribute('data-help', 'Make this participant a co-host: they may then start pages, put images on the page and arrange them, load notebook pages, expand, shrink and hide, as you can.');
|
||||
const allow = document.createElement('input');
|
||||
allow.type = 'checkbox';
|
||||
allow.className = 'allow';
|
||||
|
||||
+29
-20
@@ -479,28 +479,37 @@ export class Session {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the sheet wider, for more room to write (Andy, 2026-10-08:
|
||||
* "Widen" enlarges the page rather than zooming). Everyone's page
|
||||
* widens; it is a change to the page, so it needs the right to make
|
||||
* pages, and it ends the chance to take back an image.
|
||||
* Make the sheet fill the window, for more room to write (Andy,
|
||||
* 2026-10-08 as "Widen", which only grew the width; both ways since
|
||||
* 2026-10-11, since there is no reason width alone suits anyone).
|
||||
* Everyone's page grows; it is a change to the page, so it needs the
|
||||
* right to make pages, and it ends the chance to take back an image.
|
||||
* @param {number} width The page's new width, if wider than now.
|
||||
* @returns {boolean} Whether the page widened.
|
||||
* @param {number} height The page's new height, if taller than now.
|
||||
* @returns {boolean} Whether the page grew.
|
||||
*/
|
||||
widenPage(width) {
|
||||
expandPage(width, height) {
|
||||
const page = this.page;
|
||||
const added = Math.round(width) - page.width;
|
||||
if (!this.mayMakePages() || page.number === 0 || added <= 0) return false;
|
||||
// Equally on both sides of the PAGE as it is, writing included (the
|
||||
// sheet may lie inside a page that writing has grown; measured from
|
||||
// the sheet, the page came out short, Andy, 2026-10-08): what is on
|
||||
// the page stays where it is seen. The same whole number of units on
|
||||
// each side, since the page is centred on the screen: an odd growth
|
||||
// split 1199 and 1200 moved the page's centre half a unit, a fraction
|
||||
// of a pixel that showed as a one-pixel move on Olion (2026-10-09).
|
||||
const half = Math.floor(added / 2);
|
||||
if (half === 0) return false;
|
||||
page.baseLeft = page.left - half;
|
||||
page.baseWidth = page.width + 2 * half;
|
||||
if (!this.mayMakePages() || page.number === 0) return false;
|
||||
// Equally on both sides, and top and bottom, of the PAGE as it is,
|
||||
// writing included (the sheet may lie inside a page that writing has
|
||||
// grown; measured from the sheet, the page came out short, Andy,
|
||||
// 2026-10-08): what is on the page stays where it is seen. The same
|
||||
// whole number of units on each side, since the page is centred on
|
||||
// the screen: an odd growth split 1199 and 1200 moved the centre half
|
||||
// a unit, a pixel's fraction that showed as a one-pixel move on Olion
|
||||
// (2026-10-09). A dimension already filling the window does not grow.
|
||||
const addLeft = Math.floor((Math.round(width) - page.width) / 2);
|
||||
const addTop = Math.floor((Math.round(height) - page.height) / 2);
|
||||
if (addLeft <= 0 && addTop <= 0) return false;
|
||||
if (addLeft > 0) {
|
||||
page.baseLeft = page.left - addLeft;
|
||||
page.baseWidth = page.width + 2 * addLeft;
|
||||
}
|
||||
if (addTop > 0) {
|
||||
page.baseTop = page.top - addTop;
|
||||
page.baseHeight = page.height + 2 * addTop;
|
||||
}
|
||||
page.imagesRevision += 1;
|
||||
this.send(0, { type: 'page', page: page.descriptor() });
|
||||
this.extentChanged(true);
|
||||
@@ -510,7 +519,7 @@ export class Session {
|
||||
/**
|
||||
* Make the sheet the smallest that holds everything on the page with
|
||||
* the margin around it ("Shrink", Andy, 2026-10-08). A change to the
|
||||
* page like "Widen".
|
||||
* page like "Expand".
|
||||
* @returns {boolean} Whether the sheet changed.
|
||||
*/
|
||||
shrinkPage() {
|
||||
|
||||
+7
-1
@@ -260,6 +260,11 @@ h2 {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
/* Centre the page in the desk both ways, so that growing the sheet
|
||||
("Expand") equally on every side leaves what is on it where it is
|
||||
seen. margin:auto on an overflowing flex child computes to 0, so a
|
||||
page larger than the desk still scrolls to every edge. */
|
||||
display: flex;
|
||||
padding: 0.5rem;
|
||||
background: var(--desk);
|
||||
}
|
||||
@@ -287,7 +292,8 @@ h2 {
|
||||
|
||||
.page {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
flex: none;
|
||||
margin: auto;
|
||||
background: white;
|
||||
box-shadow: 0 1px 4px rgb(0 0 0 / 0.25);
|
||||
touch-action: none;
|
||||
|
||||
+5
-5
@@ -153,11 +153,11 @@ two gestures change the view, and none of them changes the page:
|
||||
* When the host presses **Fit** or **A4**, every participant's view
|
||||
follows, each in their own window. Your own Fit and A4 change only
|
||||
your screen.
|
||||
* **Widen**, which only the host and co-hosts have, makes the page
|
||||
itself wider, for everyone, until it fills the
|
||||
window at the present zoom. The sheet grows equally on both sides,
|
||||
so nothing on the page moves and nothing is rescaled; there is simply
|
||||
more room at either side.
|
||||
* **Expand**, which only the host and co-hosts have, makes the page
|
||||
itself fill the window, for everyone, at the present zoom, in both
|
||||
directions. The sheet grows equally on every side, so nothing on the
|
||||
page moves and nothing is rescaled; there is simply more room around
|
||||
it.
|
||||
* **Shrink**, also for the host and co-hosts, makes the page, for everyone, just large enough for what is on it,
|
||||
with the usual margin around. Nothing on it moves either.
|
||||
* **Extend** is a box, ticked to begin with. Ticked, the sheet grows
|
||||
|
||||
+5
-5
@@ -225,10 +225,10 @@ is the "write your answer here" box of a worksheet: draw it on the scan
|
||||
where the answer belongs, and the student types into their own box or
|
||||
beside yours. Only its owner can type in a box, as with any text.
|
||||
|
||||
**Widen**, among the view buttons, makes the page wider for everyone,
|
||||
until it fills your window at your present zoom: the quickest way to
|
||||
more room for writing beside an exercise. The sheet grows equally on
|
||||
both sides, so nothing on the page moves. The page keeps the new width
|
||||
**Expand**, among the view buttons, makes the page fill your window for
|
||||
everyone, at your present zoom, in both directions: the quickest way to
|
||||
more room for writing around an exercise. The sheet grows equally on
|
||||
every side, so nothing on the page moves. The page keeps the new size
|
||||
in everyone's notebook. **Shrink** is its opposite: the page becomes
|
||||
just large enough for everything on it, images and writing, with the
|
||||
margin of 5 mm around, which trims a page down to its exercise before you keep
|
||||
@@ -266,7 +266,7 @@ notebook in the toolbar first.
|
||||
In the **Participants** list of the Session window, each guest's name
|
||||
has a box **Co-host** beside it. Ticking it makes that guest a
|
||||
co-host: they may then start new pages, put images on the page and
|
||||
arrange them, load pages from their notebook, widen, shrink and hide,
|
||||
arrange them, load pages from their notebook, expand, shrink and hide,
|
||||
exactly as you can, and the buttons for it appear on their toolbar.
|
||||
Unticking it takes it back; otherwise it lasts until the session
|
||||
ends. What stays yours alone: making co-hosts, and bringing everyone's
|
||||
|
||||
@@ -113,7 +113,8 @@ from the host (or from an allowed guest, for pages and images).
|
||||
## Pages
|
||||
|
||||
Page coordinates are in units of 0.1 mm. A blank page is an A4 sheet
|
||||
in landscape, 2970 by 2100 units. "Widen" makes the sheet wider, and
|
||||
in landscape, 2970 by 2100 units. "Expand" makes the sheet fill the
|
||||
window in both directions, and
|
||||
"Shrink" makes it the bounding box of everything on the page plus the
|
||||
greater of the two margins, exactly, on every side; both are changes to the page like adding
|
||||
an image, carried in the page descriptor (its `left` and `top` edges and
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ rather than in the browser's storage.
|
||||
## The screen in one paragraph
|
||||
|
||||
The toolbar holds the pen, text, eraser and hide tools, colours and
|
||||
line widths, the view commands (Fit, A4, Widen, Shrink, Extend), the
|
||||
line widths, the view commands (Fit, A4, Expand, Shrink, Extend), the
|
||||
host's page buttons (New, Image, Notebooks), your notebook, Keep, Export
|
||||
and Session. Rest the pointer on any button for a second for its
|
||||
explanation. Each participant writes on a layer of their own that
|
||||
|
||||
+38
-28
@@ -1418,23 +1418,26 @@ class EndToEndTest(unittest.TestCase):
|
||||
self.assertEqual(placed["placed"]["y"], upward["origin"][1] + 50)
|
||||
self.assertEqual(placed["placed"]["x"], upward["origin"][0] + (upward["page"]["width"] - 300) // 2)
|
||||
|
||||
# Widen on a page that writing has grown on one side: the page
|
||||
# comes out as wide as the window, measured from the page's own
|
||||
# edges, not the sheet's (Andy, 2026-10-08).
|
||||
# Expand on a page that writing has grown on one side: the page
|
||||
# comes out as wide and as tall as the window, measured from the
|
||||
# page's own edges, not the sheet's (Andy, 2026-10-08, 2026-10-11).
|
||||
firefox.run("""
|
||||
document.getElementById('desk').dispatchEvent(new WheelEvent('wheel',
|
||||
{deltaY: 100, ctrlKey: true, clientX: 300, clientY: 300, bubbles: true, cancelable: true}));
|
||||
""")
|
||||
firefox.run("document.getElementById('zoom_widen').click();")
|
||||
widened = self.wait_until(lambda s: s["page"]["width"] > grown["page"]["width"], "the page to widen")
|
||||
firefox.run("document.getElementById('zoom_expand').click();")
|
||||
self.wait_until(lambda s: s["page"]["width"] > grown["page"]["width"]
|
||||
and s["page"]["height"] > grown["page"]["height"], "the page to expand")
|
||||
measured = firefox.run("""
|
||||
const r = window.kokkoja.renderer;
|
||||
const desk = document.getElementById('desk');
|
||||
const style = getComputedStyle(desk);
|
||||
const room = desk.offsetWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
||||
return {page: document.getElementById('page').getBoundingClientRect().width, room};
|
||||
const page = document.getElementById('page').getBoundingClientRect();
|
||||
return {width: page.width, height: page.height,
|
||||
room: desk.offsetWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight),
|
||||
roomHeight: desk.offsetHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom)};
|
||||
""")
|
||||
self.assertAlmostEqual(measured["page"], measured["room"], delta=1)
|
||||
self.assertAlmostEqual(measured["width"], measured["room"], delta=1)
|
||||
self.assertAlmostEqual(measured["height"], measured["roomHeight"], delta=1)
|
||||
|
||||
# The writer's tab is closed for the next test; the host's is cleared.
|
||||
firefox.switch_to(guest_tab)
|
||||
@@ -1654,8 +1657,8 @@ class EndToEndTest(unittest.TestCase):
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(firefox.run("return window.kokkoja.renderer.cssPixelsPerUnit;"), host_scale)
|
||||
|
||||
# Widen makes the sheet itself wider, for everyone, until it fills
|
||||
# the window at this zoom; the scale and what is in view stay.
|
||||
# Expand makes the sheet fill the window, for everyone, at this
|
||||
# zoom, in both directions; the scale and what is in view stay.
|
||||
firefox.run("""
|
||||
document.getElementById('desk').dispatchEvent(new WheelEvent('wheel',
|
||||
{deltaY: 100, ctrlKey: true, clientX: 300, clientY: 300, bubbles: true, cancelable: true}));
|
||||
@@ -1666,29 +1669,36 @@ class EndToEndTest(unittest.TestCase):
|
||||
return [Math.round(b.left), Math.round(b.top), Math.round(b.width)];
|
||||
""")
|
||||
box_before = image_box()
|
||||
firefox.run("document.getElementById('zoom_widen').click();")
|
||||
widened = zoom()
|
||||
# The sheet grew equally on both sides: nothing on it moved on the screen.
|
||||
firefox.run("document.getElementById('zoom_expand').click();")
|
||||
expanded = zoom()
|
||||
# The sheet grew equally on every side: nothing on it moved on screen.
|
||||
self.assertEqual(image_box(), box_before)
|
||||
self.assertLess(firefox.run("return window.kokkoja.session.page.baseLeft;"), 0)
|
||||
desk_width = firefox.run("""
|
||||
self.assertLess(firefox.run("return window.kokkoja.session.page.baseTop;"), 0)
|
||||
room = firefox.run("""
|
||||
const desk = document.getElementById('desk');
|
||||
const style = getComputedStyle(desk);
|
||||
return desk.offsetWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
||||
return {width: desk.offsetWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight),
|
||||
height: desk.offsetHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom)};
|
||||
""")
|
||||
self.assertAlmostEqual(widened["width"], desk_width, delta=1)
|
||||
self.assertEqual(widened["zoom"], smaller["zoom"])
|
||||
page_box = firefox.run("""
|
||||
const b = document.getElementById('page').getBoundingClientRect();
|
||||
return {width: b.width, height: b.height};
|
||||
""")
|
||||
self.assertAlmostEqual(page_box["width"], room["width"], delta=1)
|
||||
self.assertAlmostEqual(page_box["height"], room["height"], delta=1)
|
||||
self.assertEqual(expanded["zoom"], smaller["zoom"])
|
||||
wide_page = self.state()["page"]
|
||||
self.assertGreater(wide_page["width"], teacher["page"]["width"])
|
||||
self.assertEqual(wide_page["height"], teacher["page"]["height"])
|
||||
self.assertGreater(wide_page["height"], teacher["page"]["height"])
|
||||
firefox.switch_to(student_tab)
|
||||
self.wait_until(lambda s: s["page"] == wide_page, "the wider page to reach the student")
|
||||
self.assertTrue(firefox.run("return document.getElementById('zoom_widen').hidden;"))
|
||||
self.wait_until(lambda s: s["page"] == wide_page, "the expanded page to reach the student")
|
||||
self.assertTrue(firefox.run("return document.getElementById('zoom_expand').hidden;"))
|
||||
self.assertEqual(firefox.run("return window.kokkoja.session.page.baseLeft;"),
|
||||
-((wide_page["width"] - teacher["page"]["width"]) // 2))
|
||||
# The page file carries the sheet's left edge and reads back with it.
|
||||
widened_file = self.current_page("Student notebook", {}, number=3)
|
||||
self.assertRegex(widened_file, r'data-base="\d+ 2100 -\d+ 0"')
|
||||
# The page file carries the sheet's edges and reads back with them.
|
||||
expanded_file = self.current_page("Student notebook", {}, number=3)
|
||||
self.assertRegex(expanded_file, r'data-base="\d+ \d+ -\d+ -\d+"')
|
||||
firefox.switch_to(teacher_tab)
|
||||
|
||||
# Shrink makes the sheet just large enough for what is on it, with
|
||||
@@ -1725,15 +1735,15 @@ class EndToEndTest(unittest.TestCase):
|
||||
firefox.run("document.getElementById('zoom_sheet').click();")
|
||||
sheet_scale = firefox.run("return window.kokkoja.renderer.cssPixelsPerUnit;")
|
||||
self.assertLess(sheet_scale, fitted_scale)
|
||||
self.assertAlmostEqual(sheet_scale, min(desk_width / 2970, firefox.run("""
|
||||
self.assertAlmostEqual(sheet_scale, min(room["width"] / 2970, firefox.run("""
|
||||
const desk = document.getElementById('desk');
|
||||
const style = getComputedStyle(desk);
|
||||
return desk.offsetHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);
|
||||
""") / 2100), places=4)
|
||||
# Widened again, from the shrunk sheet, for the room the rest needs.
|
||||
# Expanded again, from the shrunk sheet, for the room the rest needs.
|
||||
firefox.run("document.getElementById('zoom_fit').click();")
|
||||
firefox.run("document.getElementById('zoom_widen').click();")
|
||||
self.wait_until(lambda s: s["page"]["width"] > shrunk_page["page"]["width"], "the page widened again")
|
||||
firefox.run("document.getElementById('zoom_expand').click();")
|
||||
self.wait_until(lambda s: s["page"]["width"] > shrunk_page["page"]["width"], "the page expanded again")
|
||||
firefox.run("document.getElementById('zoom_fit').click();")
|
||||
teacher = self.state()
|
||||
|
||||
|
||||
Reference in new issue
Block a user