Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- **Save ink into file works into a different board copy in Chrome** (v36, HTML overlay). Saving from `pet_board_inked.html` into `pet_board_clean.html` now asks Chrome's "allow editing?" question straight after you pick the file, before OverBoard's own "different file name" question (which used up the tap Chrome needs). If the browser still won't ask, the button stays in view and says **Tap again to allow**.
- **Ink saved into a file always shows when that file opens** (v36). The file now notes when the ink was written into it, so a browser that had used that copy before (even just to try it and clear it) no longer shows its own older, empty copy instead.
- **Tested: old board copies upgrade cleanly** (v35). Dropping an older `_board.html` on the PDF app keeps its name (no `_board_board`), puts in the newest toolbar, and the ink saved inside it still opens. A test now checks this end to end, starting from a v13 board copy.
- **Select** (v34, PDF app and HTML overlay): a new **Select** button beside ⏱ Timer. Circle ink with the pen (or tap one mark) and a dashed blue box shows what's picked, with a menu beside it:
- **Send a copy to** another class period (P2, P3…): the copy lands in the same spot in that period's ink. Tap more than one period to send it to each.
Expand Down
4 changes: 2 additions & 2 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OverBoard PDF</title>
<meta name="description" content="OverBoard: write on any PDF on your smartboard. Runs in the browser; nothing is uploaded.">
<meta name="ob-version" content="a1a6d509158d">
<meta name="ob-version" content="38fc581fca25">
<meta name="theme-color" content="#1f1f1f">
<link rel="manifest" href="manifest.json">
<link rel="icon" href="icons/icon-192.png">
Expand Down Expand Up @@ -45,7 +45,7 @@ <h2 data-t="open_again">Open again</h2>
<p class="note"><span data-th="start_note">Your PDF and your ink stay in this browser on this computer. Nothing is uploaded.
Have a Word file? In Word, choose File → Save as PDF, then drop the PDF here.
Have an HTML worksheet? Drop it here to get a <i>_board.html</i> copy you can write on.</span>
<br><a href="../" data-t="back_demo">Back to the HTML worksheet demo</a> · <a href="https://github.com/BPMData/OverBoard" data-t="about">About OverBoard</a> · <a href="report/?from=start" target="_blank" data-t="board_help">Board not working?</a> · <span id="ob-release" title="OverBoard version">v35</span></p>
<br><a href="../" data-t="back_demo">Back to the HTML worksheet demo</a> · <a href="https://github.com/BPMData/OverBoard" data-t="about">About OverBoard</a> · <a href="report/?from=start" target="_blank" data-t="board_help">Board not working?</a> · <span id="ob-release" title="OverBoard version">v36</span></p>
<p class="note ob-langpick"><label><span aria-hidden="true">🌐</span> <select id="ob-lang" aria-label="Language" data-ta="language" data-tt="language" title="Language"></select></label></p>
</div>
</main>
Expand Down
2 changes: 1 addition & 1 deletion app/report/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ <h1 data-t="r_h1">Is OverBoard not working on your board?</h1>
<p data-th="r_intro2">If something doesn't work the way the page asks, that's fine. <b>That's exactly what I need to know.</b> Just keep going.</p>
<p class="mute small" data-th="r_privacy">Nothing is sent until you press <b>Send</b> at the very end, and you'll see everything first. No worksheets, PDFs or ink are ever included.</p>
<div class="row"><button class="go big" data-go="start" data-t="r_start">Start</button></div>
<p class="mute small" style="margin-top:28px">OverBoard <span id="ob-release" title="OverBoard version">v35</span></p>
<p class="mute small" style="margin-top:28px">OverBoard <span id="ob-release" title="OverBoard version">v36</span></p>
</div></div>
</section>

Expand Down
12 changes: 6 additions & 6 deletions app/sw.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// ===== GENERATED by tools/build.py: every file the app needs, with the start of its SHA-256. Do not edit by hand. =====
const VERSION = '9b25193c784a';
const VERSION = '471e7c21ebea';
const FILES = {
"../overlay/ink_overlay.html": "0e27675d1ec4908f",
"../overlay/ink_overlay.html": "42bade453c738a0a",
"../shared/ink-core.js": "84be8f49eeb4d2d3",
"../shared/strings.js": "e84c83bf93320729",
"../shared/strings.js": "d85fbc3cf3f1c436",
"../shared/toolbar.css": "55e88770a7c0f1c2",
"app.css": "eb0f282d02685caf",
"embed.js": "ea50a9ff4e960dd4",
Expand All @@ -14,14 +14,14 @@ const FILES = {
"icons/icon-192.png": "d245e15b36475003",
"icons/icon-512.png": "17c1021fe2a0ade1",
"icons/maskable-512.png": "0c58f1bdccc9eda9",
"index.html": "74f77552bac14322",
"index.html": "c03b8fc0802c288d",
"ink.js": "253f8d907ccfbc1b",
"libs.js": "c09f60186ab9029a",
"main.js": "48ecaa409acb49b9",
"manifest.json": "f7ee4a6c6f83cd40",
"notebook.js": "47bcfd4f80712344",
"offline.js": "6504935b2738711a",
"report/index.html": "720cab90cc9b146f",
"report/index.html": "9c8cd50b68eafb8c",
"store.js": "66af54cd32e6cbd2",
"textlayer.js": "1911308ed3e2a8b5",
"vendor/[email protected]/LICENSE.md": "f2c9fc00fdb66eb9",
Expand Down Expand Up @@ -214,7 +214,7 @@ const FILES = {
"vendor/[email protected]/standard_fonts/LiberationSans-BoldItalic.ttf": "a224075ac17495ad",
"vendor/[email protected]/standard_fonts/LiberationSans-Italic.ttf": "832b4406dbef2362",
"vendor/[email protected]/standard_fonts/LiberationSans-Regular.ttf": "f8ace1f892b2bd9d",
"version.json": "f2e202f1f6845553",
"version.json": "0c4d0798795a815b",
"viewer.js": "648b4479c5b68b93"
};
// ===== END GENERATED =====
Expand Down
2 changes: 1 addition & 1 deletion app/version.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"v": "a1a6d509158d",
"v": "38fc581fca25",
"js": [
"embed.js",
"export.js",
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Notes for contributors: how each part is built and why. What's planned next is i
- **Layers.** Pen ink on `#ink-canvas`; highlights on `#ink-hl` underneath with `mix-blend-mode: multiply`; eraser strokes cut through both.
- **Rendering.** Strokes are quadratic curves through sample midpoints, with an exponential smoothing filter on input (`SMOOTHING` level 0–8). Live drawing renders the identical curve piece by piece.
- **Input (SMART Board on macOS, observed with `tools/board-probe.html`).** Pen tip → `pointerType: "pen"`, `buttons: 1`. Palm/fist/side of hand → `"pen"` with `buttons: 32` (eraser). Finger and the pen's round end → `"mouse"`. Contact size is always 1×1. Only one pointer reaches the browser at a time. A still finger is held back by the driver until it moves.
- **Saving.** Browser IndexedDB (database `ink-data`, store `ink`, key `ink-v2:<path>:<title>`; v21+), plus optional File System Access write into the `<script id="ink-data">` block of the .html file.
- **Saving.** Browser IndexedDB (database `ink-data`, store `ink`, key `ink-v2:<path>:<title>`; v21+), plus optional File System Access write into the `<script id="ink-data">` block of the .html file. Ink written into the file carries `w` (when it was written; v36). On load, the file's ink counts as new as `max(t, w)` against the browser's copy (`t` = last change), so ink copied into another board copy beats that copy's older browser ink. Linking a file asks for write permission straight after the file window, before the "different file name" `confirm()`, which in Chrome uses up the tap the permission prompt needs; if the browser still refuses, the File menu stays open with **Tap again to allow** on the button.
- **Print.** `beforeprint` redraws each page's strokes as vectors at `PRINT_SCALE` onto per-page canvases.

## The PDF app (v2)
Expand Down
28 changes: 24 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ <h2>Exit ticket</h2>
<div class="lines"><div></div><div></div><div></div><div></div></div>
<div class="foot">OverBoard · page 2 / 2 · Your ink saves in this browser only. Nothing is uploaded.</div>
</div>
<!-- ===== INK OVERLAY START (v35) =====
<!-- ===== INK OVERLAY START (v36) =====
Smartboard writing layer. Paste this whole block just before </body> in any .html file.
SMART BOARD: pen tip writes. Palm, fist or side of hand erases (the board reports it as an eraser).
Finger (and the round end of the SMART pen) scrolls the page; the "Finger" button switches it to drawing if you lose the pen.
Expand Down Expand Up @@ -1637,6 +1637,7 @@ <h2>Exit ticket</h2>
"confirm_remove_pdf": ["Remove {list} and its ink from this PDF?\n\nUndo can't bring it back.", "¿Quitar {list} y su tinta de este PDF?\n\nDeshacer no puede recuperarla.", "要从此 PDF 中删除 {list} 及其笔迹吗?\n\n撤销无法恢复。", "Alisin ang {list} at ang tinta nito sa PDF na ito?\n\nHindi na ito maibabalik ng Undo.", "Xóa {list} và nét mực của nó khỏi PDF này?\n\nHoàn tác không lấy lại được.", "Retirer {list} et son encre de ce PDF ?\n\nAnnuler ne pourra pas le faire revenir.", "Remover {list} e a tinta dele deste PDF?\n\nDesfazer não traz de volta.", "هل تزيل {list} وحبره من ملف PDF هذا؟\n\nلا يمكن للتراجع إعادته."],
"explain_pick": ["Ink already saves in this browser. This also saves it INSIDE the file. In the window that opens (it says \"Open\"), pick: {f}", "La tinta ya se guarda en este navegador. Esto también la guarda DENTRO del archivo. En la ventana que se abre (dice \"Abrir\"), elige: {f}", "笔迹已经保存在此浏览器中。这会同时把它保存到文件内部。在打开的窗口中(显示“打开”),选择:{f}", "Nase-save na ang tinta sa browser na ito. Sine-save din nito ang tinta SA LOOB ng file. Sa window na lalabas (nakasulat ay \"Open\"), piliin ang: {f}", "Nét mực đã được lưu trong trình duyệt này. Lệnh này lưu thêm vào BÊN TRONG tệp. Trong cửa sổ hiện ra (ghi \"Mở\"), hãy chọn: {f}", "L'encre est déjà enregistrée dans ce navigateur. Ceci l'enregistre aussi DANS le fichier. Dans la fenêtre qui s'ouvre (elle indique « Ouvrir »), choisissez : {f}", "A tinta já é salva neste navegador. Isto também a salva DENTRO do arquivo. Na janela que abrir (diz \"Abrir\"), escolha: {f}", "الحبر محفوظ بالفعل في هذا المتصفح. هذا يحفظه أيضًا داخل الملف. في النافذة التي تظهر (مكتوب فيها \"فتح\")، اختر: {f}"],
"this_worksheet": ["this worksheet", "esta hoja", "此练习页", "worksheet na ito", "bài tập này", "ce document", "esta folha", "ورقة العمل هذه"],
"tap_again_allow": ["Tap again to allow", "Toca otra vez para permitir", "再点一次以允许", "I-tap ulit para payagan", "Chạm lần nữa để cho phép", "Touchez encore pour autoriser", "Toque de novo para permitir", "اضغط مرة أخرى للسماح"],
"tap_again_pick": ["Tap again to pick file", "Toca otra vez para elegir", "再点一次选择文件", "I-tap ulit para pumili", "Chạm lần nữa để chọn", "Touchez encore pour choisir", "Toque de novo para escolher", "اضغط مرة أخرى لاختيار الملف"],
"st_loaded_file": ["{p} · ink loaded from file", "{p} · tinta cargada del archivo", "{p} · 已从文件载入笔迹", "{p} · na-load ang tinta mula sa file", "{p} · đã mở nét mực từ tệp", "{p} · encre chargée depuis le fichier", "{p} · tinta carregada do arquivo", "{p} · تم تحميل الحبر من الملف"],
"st_restored": ["{p} · ink restored from this browser", "{p} · tinta recuperada de este navegador", "{p} · 已从此浏览器恢复笔迹", "{p} · naibalik ang tinta mula sa browser na ito", "{p} · đã khôi phục nét mực từ trình duyệt này", "{p} · encre restaurée depuis ce navigateur", "{p} · tinta recuperada deste navegador", "{p} · تمت استعادة الحبر من هذا المتصفح"],
Expand Down Expand Up @@ -1992,9 +1993,13 @@ <h2>Exit ticket</h2>
var o = parse(s);
if (!o || (o.t || 0) <= t) { try { localStorage.removeItem(KEY); } catch(e){} }
}
/* Ink written into a file carries w: when it was written. Ink copied into another board copy (Save ink into file,
then a different file) can have been drawn before that copy's own ink in this browser, yet it is the newer copy. */
var shownT = 0; // how new the ink on screen is, to compare with the browser's copy
function load(){
var emb = dataEl ? parse(dataEl.textContent) : null, loc = lsCopy = parse(getLS(KEY)), src = '';
if (loc && (!emb || (loc.t || 0) > (emb.t || 0))) { D = loc; src = 'browser'; } // newest copy wins; a tie goes to the file
var et = emb ? Math.max(emb.t || 0, emb.w || 0) : 0;
if (loc && (!emb || (loc.t || 0) > et)) { D = loc; src = 'browser'; } // newest copy wins; a tie goes to the file
else if (emb) { D = emb; src = 'file'; }
else {
D = fresh();
Expand All @@ -2004,6 +2009,8 @@ <h2>Exit ticket</h2>
} catch(e){}
}
if (!Object.keys(D.periods).length) D = fresh();
shownT = src === 'file' ? et : D.t || 0;
delete D.w;
shortNames();
if (!D.periods[D.active]) D.active = Object.keys(D.periods)[0];
strokes = D.periods[D.active];
Expand All @@ -2012,7 +2019,7 @@ <h2>Exit ticket</h2>
function loadDb(){ // then the IndexedDB copy, if it is newer than what's on screen
return inkTx('readonly', function(st){ return st.get(KEY); }).then(function(r){
var got = r.ok && r.val && r.val.periods && typeof r.val.periods === 'object' ? r.val : null, src = '';
if (got && (got.t || 0) > (D.t || 0)) {
if (got && (got.t || 0) > shownT) {
D = got; shortNames();
if (!Object.keys(D.periods).length) D = fresh();
if (!D.periods[D.active]) D.active = Object.keys(D.periods)[0];
Expand Down Expand Up @@ -2275,6 +2282,9 @@ <h2>Exit ticket</h2>
async function linkFile(){
var hs = await window.showOpenFilePicker({ types: [{ description: 'This worksheet (.html)', accept: { 'text/html': ['.html', '.htm'] } }] });
var h = hs[0], base = decodeURIComponent(location.pathname.split('/').pop());
// ask to write right away, while the tap that opened the file window still counts: in Chrome, our question
// below uses it up, and then the browser refuses without asking
try { if ((await h.queryPermission({ mode: 'readwrite' })) !== 'granted') await h.requestPermission({ mode: 'readwrite' }); } catch(e){}
if (base && h.name !== base && !confirm(tr('confirm_other_file', { a: base, b: h.name }))) return false;
var txt = await (await h.getFile()).text();
if (injectInk(txt, '{}') === null) { setStatus(tr('st_no_ink_block')); return false; }
Expand All @@ -2287,7 +2297,7 @@ <h2>Exit ticket</h2>
try {
if (!(await hasPermission(ask))) { setStatus(tr('st_tap_allow', { p: D.active })); return false; }
var txt = await (await fileHandle.getFile()).text();
var out = injectInk(txt, JSON.stringify(D));
var out = injectInk(txt, JSON.stringify(Object.assign({}, D, { w: Date.now() }))); // w: when it was written (see load)
if (out === null) { setStatus(tr('st_linked_no_block')); return false; }
var w = await fileHandle.createWritable();
try { await w.write(out); await w.close(); }
Expand Down Expand Up @@ -2316,8 +2326,18 @@ <h2>Exit ticket</h2>
var ok = await saveFile(forcePick);
if (ok === null) return;
if (ok) flashBtn(btn, tr(wasLinked ? 'already_saved' : 'saved_to_file'), 'good');
else if (fileHandle && !(await hasPermission(false))) askAgain(btn);
else flashBtn(btn, tr('not_saved'), 'warn');
}
/* The browser wouldn't ask for permission to write (it only asks right after a tap). Keep the menu open and
say so on the button: the next tap there asks. */
function askAgain(btn){
if (fileMenu.el.hidden) fileMenu.show(true);
clearTimeout(btn._flash); if (!btn.classList.contains('warn')) btn._label = btn.textContent;
btn.classList.remove('good'); btn.classList.add('warn'); btn.textContent = tr('tap_again_allow');
btn._flash = setTimeout(function(){ btn.classList.remove('warn'); btn.textContent = btn._label; }, 10000);
setStatus(tr('st_file_linked_again'));
}

/* ---------- toolbar ---------- */
function isPreset(c){ return !!bar.querySelector('[data-color="' + c + '"]'); }
Expand Down
Loading
Loading