2026-10-06 15:58:02 +02:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > Kokkoja</ title >
< link rel = "stylesheet" href = "kokkoja.css" >
< script type = "module" src = "js/main.js" ></ script >
</ head >
< body >
< main id = "start" hidden >
< h1 > Kokkoja</ h1 >
< label for = "name" > Your name, as others will see it</ label >
< input id = "name" type = "text" maxlength = "40" autocomplete = "off" >
< label for = "notebook" > Notebook for the pages of this session</ label >
2026-10-10 19:01:20 +02:00
< select id = "notebook" class = "notebook_pick"
data-help = "The notebook this session’ s pages are saved in. The last entry makes a new notebook." ></ select >
< input id = "notebook_name" type = "text" maxlength = "100" autocomplete = "off" spellcheck = "false"
placeholder = "Name of the new notebook" aria-label = "Name of the new notebook" hidden >
2026-10-06 15:58:02 +02:00
< p id = "notebook_note" class = "note notebook_directory" ></ p >
2026-10-10 19:01:20 +02:00
< section id = "start_choice" >
2026-10-06 15:58:02 +02:00
< h2 > Start a session</ h2 >
< p > You will be given an invitation to send to the others.</ p >
< button id = "start_session" type = "button" > Start a session</ button >
</ section >
2026-10-10 19:01:20 +02:00
< section id = "join_choice" >
2026-10-06 15:58:02 +02:00
< h2 > Join a session</ h2 >
< label for = "invitation_entry" > Invitation</ label >
< input id = "invitation_entry" type = "text" autocomplete = "off" spellcheck = "false" >
< button id = "join_session" type = "button" > Join</ button >
< p class = "note" >< a id = "open_installed" href = "#" hidden > Join with the Kokkoja program installed on this computer instead</ a ></ p >
</ section >
< p id = "start_message" class = "message" role = "alert" ></ p >
</ main >
< div id = "session" hidden >
< header class = "toolbar" >
2026-10-11 13:17:22 +02:00
< div id = "drawing" class = "drawing" aria-label = "Drawing" >
2026-10-06 15:58:02 +02:00
< div class = "group" role = "radiogroup" aria-label = "Tool" >
< button type = "button" data-tool = "pen" aria-pressed = "true"
data-help = "Write on the page. Only your own writing can be erased." > Pen</ button >
< button type = "button" data-tool = "text" aria-pressed = "false"
2026-10-14 14:00:47 +02:00
data-help = "Type on the page. Tap where the text should begin, or drag open a rectangle in which the text wraps and which grows downward as you type; its corners are marked in blue on the screen only. Tap your own text to change it; rest the pen on it to move it, or near a corner of a rectangle to resize it, or use Arrange." > Text</ button >
< button type = "button" id = "shape_tool" data-tool = "shape" aria-pressed = "false" aria-haspopup = "menu" aria-expanded = "false" data-name = "Shapes"
data-help = "Draw the shape named on the button, in the pen’ s colour and line width. Hold the button down, or press it with the right button, for the other shapes." > Rectangle</ button >
< div id = "shape_menu" class = "popup menu" role = "menu" hidden >
< button type = "button" class = "menu_item" role = "menuitem" data-shape = "rectangle"
data-help = "Rectangle: drag open the rectangle from one corner to the opposite one." > Rectangle</ button >
2026-10-14 20:38:29 +02:00
< button type = "button" class = "menu_item" role = "menuitem" data-shape = "circle"
data-help = "Circle: press at the centre and drag out to the edge, in any direction." > Circle</ button >
2026-10-14 14:00:47 +02:00
< button type = "button" class = "menu_item" role = "menuitem" data-shape = "ellipse"
data-help = "Ellipse: drag open the rectangle the ellipse fills." > Ellipse</ button >
< button type = "button" class = "menu_item" role = "menuitem" data-shape = "line"
data-help = "Line: tap each point of the line in turn; a drag gives its first two. Tap the last point again to finish, or the first point to close the shape. Backspace takes back the last point, Escape finishes." > Line</ button >
< button type = "button" class = "menu_item" role = "menuitem" data-shape = "arrow"
data-help = "Arrow: drag from the tail to the tip. The head is filled, its width from the line width." > Arrow</ button >
< hr >
< div class = "menu_title" > Fill the shapes with</ div >
< div class = "group fills" id = "shape_fill" role = "radiogroup" aria-label = "Fill" ></ div >
</ div >
2026-10-06 15:58:02 +02:00
</ div >
2026-10-11 13:17:22 +02:00
< div id = "settings" class = "settings" >
2026-10-06 15:58:02 +02:00
< div class = "group" id = "colors" role = "radiogroup" aria-label = "Color" >
< button id = "more_colors" type = "button" class = "swatch more"
data-help = "Choose another color. It is added here." > +</ button >
</ div >
2026-10-14 14:00:47 +02:00
< div id = "color_palette" class = "popup palette" hidden ></ div >
2026-10-06 15:58:02 +02:00
< div class = "group" id = "widths" role = "radiogroup" aria-label = "Line width" ></ div >
< div class = "group" id = "text_style" hidden >
< select id = "text_font" aria-label = "Font" data-help = "The font: a sans-serif, a serif or a monospaced one, as this computer has them." >
< option value = "sans-serif" style = "font-family: sans-serif" > Sans</ option >
< option value = "serif" style = "font-family: serif" > Serif</ option >
< option value = "monospace" style = "font-family: monospace" > Mono</ option >
</ select >
< input id = "text_size" type = "number" min = "6" max = "100" step = "1" value = "14"
aria-label = "Text size in points" data-help = "Text size in points." >
</ div >
2026-10-11 13:17:22 +02:00
</ div >
2026-10-14 00:01:45 +02:00
< div class = "group after_settings" role = "radiogroup" aria-label = "Hide, Arrange and Eraser" >
2026-10-11 13:17:22 +02:00
< button type = "button" data-tool = "hide" aria-pressed = "false" hidden
2026-10-14 00:01:45 +02:00
data-help = "Hide part of the page for everyone: drag open a rectangle, and what lies under it is covered in white, marked by blue corners. Rest the pen on it to move it, or near a corner to resize it, or use Arrange; a tap of the eraser removes it." > Hide</ button >
< button type = "button" data-tool = "arrange" aria-pressed = "false"
2026-10-14 14:00:47 +02:00
data-help = "Move and resize: the corners of every image are marked in blue, as those of Hides and text rectangles always are. Drag inside an image, a Hide or a text rectangle of yours to move it, drag a corner to resize it (an image keeps its shape). A press elsewhere does nothing. With any other tool, resting the pen on one of them for half a second does the same." > Arrange</ button >
2026-10-11 13:17:22 +02:00
< button type = "button" data-tool = "eraser" aria-pressed = "false"
data-help = "Erase your own strokes and text by moving over them. A tap on an image, or on a Hide rectangle, removes it, if you are the host or a co-host (or added the image yourself). Two quick taps on empty paper, away from anything the eraser would remove, undo your latest mark; again, and the one before." > Eraser</ button >
</ div >
< button id = "undo" type = "button" disabled
data-help = "Take back your latest mark: a stroke, an erasure, a text block typed or moved, a Hide rectangle. Again for the one before. Also Ctrl+Z (Command+Z on a Mac), or two quick taps of the eraser on empty paper. Only your own marks, and only on this page since you opened it." > Undo</ button >
</ div >
2026-10-10 19:01:20 +02:00
< div class = "toolbar_right" >
2026-10-11 17:34:24 +02:00
< div class = "group" id = "host_tools" >
2026-10-14 01:07:53 +02:00
< button id = "page_menu_button" type = "button" aria-haspopup = "menu" aria-expanded = "false"
2026-10-14 01:54:26 +02:00
data-help = "The page and the view: fit the page to the window, show it at its normal scale, make it larger or smaller, and whether it grows as you write." > Page</ button >
2026-10-14 01:07:53 +02:00
< div id = "page_menu" class = "popup menu" role = "menu" hidden >
< div class = "menu_title" > Change the display of the page</ div >
< button id = "zoom_fit" type = "button" class = "menu_item" role = "menuitem"
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 to the window</ button >
< button id = "zoom_sheet" type = "button" class = "menu_item" role = "menuitem"
2026-10-14 01:54:26 +02:00
data-help = "Show the page at the scale a new page has, one full page filling the window. A shrunk page is then seen at its own size rather than enlarged. Pressed by the host, it does so on every screen." > Normal scale</ button >
2026-10-14 01:07:53 +02:00
< hr >
< div class = "menu_title" > Change the size of the page</ div >
< button id = "zoom_expand" type = "button" class = "menu_item" role = "menuitem" hidden
data-help = "Make the page fill the window, for everyone, at this zoom, in both directions. Nothing on it moves." > Expand to the window</ button >
< button id = "zoom_shrink" type = "button" class = "menu_item" role = "menuitem" 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 to the contents</ button >
< hr >
< label class = "menu_item toggle" role = "menuitemcheckbox"
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." >
< input id = "extend" type = "checkbox" checked > Extend the page while writing
</ label >
</ div >
2026-10-06 15:58:02 +02:00
< button id = "new_page" type = "button"
data-help = "Start a new blank page for everyone. The current page is kept in each notebook." > New</ button >
< button id = "load_image" type = "button"
2026-10-10 19:01:20 +02:00
data-help = "Put an image file, such as a scanned exercise, on the page for everyone: below the images already there, centred, at its own size. Rest the pen on an image to move it, or near a corner to scale it; it comes to the front. A tap of the eraser on an image removes it; writing on it stays." > Image</ button >
2026-10-06 15:58:02 +02:00
< button id = "load_notebook_page" type = "button"
2026-10-11 17:34:24 +02:00
data-help = "Your notebooks and the pages kept in them, to look at or to delete. The host and co-hosts can start a new page for everyone from a kept page, with everything on it; the current page is then kept in each notebook." > Notebooks</ button >
2026-10-06 15:58:02 +02:00
</ div >
2026-10-10 19:01:20 +02:00
< div class = "group" aria-label = "Notebook" >
< select id = "session_notebook" class = "notebook_pick" aria-label = "Current notebook"
data-help = "The notebook the page is saved in. Choosing another continues the page there; the last entry makes a new notebook." ></ select >
< input id = "session_notebook_name" type = "text" maxlength = "100" autocomplete = "off" spellcheck = "false"
placeholder = "Name of the new notebook" aria-label = "Name of the new notebook" hidden >
< button id = "keep_page" type = "button"
data-help = "Keep a dated copy of the page as it is now. The page is also kept by itself whenever it is about to be replaced." > Keep</ button >
< button id = "export_page" type = "button"
data-help = "Save a picture of the page, as it is shown here, in a PNG file at a place you choose." > Export</ button >
</ div >
< button id = "session_button" type = "button"
data-help = "Who is here, and the invitation to send to others." > Session</ button >
2026-10-15 17:17:45 +02:00
< button id = "help" type = "button" data-help = "One click shows the explanations of every command, as one text in a window. Two quick clicks show where the documentation is." > Help</ button >
< div id = "help_popup" class = "popup help_popup" hidden > Documentation website coming soon!</ div >
2026-10-06 15:58:02 +02:00
</ div >
</ header >
2026-10-10 19:01:20 +02:00
< div id = "notice" class = "notice" hidden ></ div >
2026-10-06 15:58:02 +02:00
< div class = "workspace" >
< div id = "desk" class = "desk" >
< div id = "page" class = "page" ></ div >
</ div >
2026-10-10 19:01:20 +02:00
</ div >
</ div >
2026-10-06 15:58:02 +02:00
2026-10-10 19:01:20 +02:00
< dialog id = "session_dialog" class = "chooser session" >
< header >
< h2 > Session</ h2 >
< button id = "session_close" type = "button" aria-label = "Close" > × </ button >
</ header >
< div class = "session_body" >
< h3 > Participants</ h3 >
< ul id = "participants" ></ ul >
< h3 > Invitation</ h3 >
< div class = "invitation_line" >
2026-10-06 15:58:02 +02:00
< input id = "invitation" type = "text" readonly spellcheck = "false" >
< button id = "copy_invitation" type = "button"
data-help = "Copy the invitation, to send to the others by any means." > Copy</ button >
2026-10-10 19:01:20 +02:00
</ div >
2026-10-14 01:07:53 +02:00
< div id = "invitation_code" class = "invitation_code" hidden aria-label = "QR code"
2026-10-10 19:01:20 +02:00
data-help = "The invitation as a QR code. Point the camera of a phone or a tablet at it, and the link opens there." ></ div >
< p class = "note session_state" >
< span id = "page_number" class = "page_number" ></ span >
< span id = "status" class = "status" ></ span >
< span id = "save_status" class = "save_status" ></ span >
</ p >
< p class = "note notebook_directory" ></ p >
< h3 > Log</ h3 >
< div class = "log_line" >
< pre id = "event_log" class = "event_log" ></ pre >
< button id = "copy_log" type = "button"
data-help = "Copy the log: what happened in this session and every press and release of the pen, for finding a fault." > Copy</ button >
</ div >
2026-10-06 15:58:02 +02:00
</ div >
2026-10-10 19:01:20 +02:00
</ dialog >
2026-10-06 15:58:02 +02:00
2026-10-14 01:07:53 +02:00
< dialog id = "manual_dialog" class = "chooser manual" >
< header >
< h2 > Help</ h2 >
< button id = "copy_manual" type = "button" class = "action"
data-help = "Copy this text." > Copy</ button >
< button id = "manual_close" type = "button" aria-label = "Close" > × </ button >
</ header >
2026-10-15 17:17:45 +02:00
< div id = "manual_text" class = "manual_text" tabindex = "0" autofocus ></ div >
2026-10-14 01:07:53 +02:00
</ dialog >
2026-10-06 15:58:02 +02:00
< dialog id = "notebook_chooser" class = "chooser" >
< header >
< h2 > Notebooks</ h2 >
2026-10-11 16:59:03 +02:00
< button id = "chooser_delete" type = "button" class = "delete" hidden
data-help = "Delete the marked notebooks and pages. The first press says what will happen; the second does it." > Delete</ button >
2026-10-06 15:58:02 +02:00
< button id = "chooser_close" type = "button" aria-label = "Close" > × </ button >
</ header >
< div class = "chooser_body" >
< nav id = "chooser_notebooks" class = "chooser_notebooks" ></ nav >
< div id = "chooser_pages" class = "chooser_pages" ></ div >
</ div >
< p id = "chooser_message" class = "note" ></ p >
</ dialog >
< dialog id = "file_chooser" class = "chooser" >
< header >
< h2 id = "files_title" > Image</ h2 >
< button id = "files_close" type = "button" aria-label = "Close" > × </ button >
</ header >
< div class = "files_place" >
< button id = "files_up" type = "button" > Up</ button >
< input id = "files_directory" type = "text" spellcheck = "false" autocomplete = "off"
aria-label = "Directory" >
</ div >
< div class = "files_body" >
< nav id = "files_directories" class = "files_directories" ></ nav >
< div id = "files_entries" class = "files_entries" ></ div >
</ div >
< div id = "files_save" class = "files_save" hidden >
< input id = "files_name" type = "text" spellcheck = "false" autocomplete = "off"
aria-label = "File name" >
< button id = "files_save_here" type = "button" > Export</ button >
</ div >
< p id = "files_message" class = "note" ></ p >
</ dialog >
</ body >
</ html >