The Page menu, Help, and the manual from the tooltips
The page and view commands are in a menu under "Page", with grey titles over the display and size sections. Help, at the far right, shows a note for now; with Ctrl (Command on a Mac) held it shows the explanations of every command in one text, alphabetical, wrapped at 80 columns, a shared name prefixed by its context. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
8ecf3e94a6
commit
35c4f434f3
5 files changed
+419
-55
No files matched your search
@@ -1484,6 +1484,109 @@ class EndToEndTest(unittest.TestCase):
|
||||
choose("arrange")
|
||||
self.assertEqual(cues(), ["text"])
|
||||
|
||||
def test_page_menu_and_help(self):
|
||||
"""Andy, 2026-10-14: the page and view commands are in a Page menu,
|
||||
a popup of Kokkoja's own under the button, closed by a press on an
|
||||
item, elsewhere, or Escape; Help shows a note for now; one popup
|
||||
at a time."""
|
||||
firefox = self.firefox
|
||||
firefox.go(self.address("Late"))
|
||||
self.enter_name("Menuist", "start_session")
|
||||
self.wait_until(lambda s: s["page"]["number"] == 1, "the page")
|
||||
hidden = lambda id: firefox.run(f"return document.getElementById('{id}').hidden;")
|
||||
click = lambda id: firefox.run(f"document.getElementById('{id}').click();")
|
||||
box = lambda id: firefox.run(f"const b = document.getElementById('{id}').getBoundingClientRect(); return [b.left, b.top, b.right, b.bottom];")
|
||||
self.assertTrue(hidden("page_menu"))
|
||||
self.assertIsNone(firefox.run("return document.querySelector('.page_view');"), "the middle group is gone")
|
||||
# The Page button is the first of the right-hand group; Help the last of all.
|
||||
self.assertEqual(firefox.run("return [...document.querySelectorAll('.toolbar button')].at(-1).id;"), "help")
|
||||
self.assertEqual(firefox.run("return document.querySelector('.toolbar_right button').id;"), "page_menu_button")
|
||||
|
||||
# Open: below the button, left edges aligned, within the window.
|
||||
click("page_menu_button")
|
||||
self.assertFalse(hidden("page_menu"))
|
||||
self.assertEqual(firefox.run("return document.getElementById('page_menu_button').getAttribute('aria-expanded');"), "true")
|
||||
button, menu = box("page_menu_button"), box("page_menu")
|
||||
self.assertAlmostEqual(menu[0], button[0], delta=1)
|
||||
self.assertGreater(menu[1], button[3])
|
||||
self.assertLess(menu[2], firefox.run("return window.innerWidth;"))
|
||||
items = firefox.run("return [...document.querySelectorAll('#page_menu .menu_item')].filter((e) => !e.hidden).map((e) => e.textContent.trim());")
|
||||
self.assertEqual(items, ["Fit to the window", "A4 scale", "Expand to the window",
|
||||
"Shrink to the contents", "Extend the page while writing"])
|
||||
# Two grey titles, over the first two sections, in the muted colour.
|
||||
self.assertEqual(firefox.run("return [...document.querySelectorAll('#page_menu .menu_title')].map((e) => e.textContent);"),
|
||||
["Change the display of the page", "Change the size of the page"])
|
||||
self.assertEqual(firefox.run("const t = document.querySelector('#page_menu .menu_title'); return [getComputedStyle(t).color, getComputedStyle(t).fontStyle];"),
|
||||
firefox.run("return [getComputedStyle(document.getElementById('undo')).color, 'normal'];"))
|
||||
# An item's press runs it and closes the menu.
|
||||
click("zoom_sheet")
|
||||
self.assertTrue(hidden("page_menu"))
|
||||
# The checkbox item toggles Extend and closes too.
|
||||
click("page_menu_button")
|
||||
self.assertTrue(firefox.run("return document.getElementById('extend').checked;"))
|
||||
click("extend")
|
||||
self.assertFalse(firefox.run("return document.getElementById('extend').checked;"))
|
||||
self.assertTrue(hidden("page_menu"))
|
||||
click("extend") # back on, for the tests that follow
|
||||
# Escape closes; so does a press elsewhere.
|
||||
click("page_menu_button")
|
||||
self.assertFalse(hidden("page_menu"))
|
||||
firefox.chord("\ue00c")
|
||||
self.assertTrue(hidden("page_menu"))
|
||||
click("page_menu_button")
|
||||
firefox.run("document.getElementById('page').dispatchEvent(new PointerEvent('pointerdown', {bubbles: true}));")
|
||||
self.assertTrue(hidden("page_menu"))
|
||||
|
||||
# Help: a note for now; opening it closes the menu, and the reverse.
|
||||
click("page_menu_button")
|
||||
click("help")
|
||||
self.assertFalse(hidden("help_popup"))
|
||||
self.assertTrue(hidden("page_menu"))
|
||||
# At the far right, the note's right edge aligns with the button's, inside the window.
|
||||
help_button, note = box("help"), box("help_popup")
|
||||
self.assertAlmostEqual(note[2], help_button[2], delta=1)
|
||||
self.assertLess(note[2], firefox.run("return window.innerWidth;"))
|
||||
self.assertEqual(firefox.run("return document.getElementById('help_popup').textContent.trim();"), "Help is coming!")
|
||||
click("page_menu_button")
|
||||
self.assertTrue(hidden("help_popup"))
|
||||
self.assertFalse(hidden("page_menu"))
|
||||
firefox.chord("\ue00c")
|
||||
|
||||
# Ctrl-click on Help: the tooltips of every command as one text, in
|
||||
# a window: the title, then each control in alphabetical order,
|
||||
# its name on a line, its explanation wrapped at 80 columns, and
|
||||
# a blank line after.
|
||||
firefox.run("document.getElementById('help').dispatchEvent(new MouseEvent('click', {ctrlKey: true, bubbles: true}));")
|
||||
self.assertTrue(firefox.run("return document.getElementById('manual_dialog').open;"))
|
||||
self.assertTrue(hidden("help_popup"), "the note did not open as well")
|
||||
manual = firefox.run("return document.getElementById('manual_text').textContent;")
|
||||
self.assertTrue(manual.startswith("User interface actions\n\n"))
|
||||
blocks = manual.split("\n\n")[1:]
|
||||
names = [block.split("\n")[0] for block in blocks if block]
|
||||
self.assertEqual(names, sorted(names, key=str.casefold), "alphabetical")
|
||||
self.assertIn("Pen", names)
|
||||
self.assertIn("Color", names) # the swatches as one entry
|
||||
self.assertIn("Line width", names) # the widths as one entry
|
||||
self.assertIn("Notebook for the pages of this session", names)
|
||||
self.assertIn("QR code", names)
|
||||
# A name two controls share gets each one's context: the nearest heading above it.
|
||||
self.assertIn("Invitation: Copy", names)
|
||||
self.assertIn("Log: Copy", names)
|
||||
self.assertNotIn("Copy", names)
|
||||
self.assertEqual(len(names), len(set(names)), "no two entries of one name")
|
||||
self.assertIn("\nPen\nWrite on the page. Only your own writing can be erased.\n", manual)
|
||||
self.assertIn("\nFit to the window\nShow the whole page in the window.", manual)
|
||||
self.assertTrue(all(len(line) <= 80 for line in manual.split("\n")), "wrapped at 80")
|
||||
self.assertTrue(any(len(line) > 60 for line in manual.split("\n")), "filled, not one word a line")
|
||||
# Every tooltip is in it; those that differ only by a number (the
|
||||
# line widths) as one entry, so the numbers are set aside.
|
||||
helps = firefox.run("return [...document.querySelectorAll('[data-help]')].filter((e) => !e.closest('#manual_dialog')).map((e) => e.getAttribute('data-help'));")
|
||||
unwrapped = re.sub(r"\d+(?:\.\d+)?", "#", manual.replace("\n", " "))
|
||||
for help in set(helps):
|
||||
self.assertIn(re.sub(r"\d+(?:\.\d+)?", "#", help), unwrapped, help[:40])
|
||||
firefox.run("document.getElementById('manual_close').click();")
|
||||
self.assertFalse(firefox.run("return document.getElementById('manual_dialog').open;"))
|
||||
|
||||
def test_text_being_typed_stays_on_the_page_left(self):
|
||||
"""Andy, 2026-10-06: a guest was typing when the host pressed New,
|
||||
and the text reappeared on the new page."""
|
||||
|
||||
Reference in new issue
Block a user