From a2fb3b056ae1caf5c8b558cd05a083d67dcb0258 Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Mon, 19 Oct 2026 17:01:02 -0400 Subject: [PATCH] Add free-type spell checker for students Co-Authored-By: Claude Sonnet 5.5 --- package-lock.json | 46 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 4 +++- public/app.js | 31 +++++++++++++++++++++++++++++++ public/index.html | 15 +++++++++++++++ server.js | 12 ++++++++++++ 5 files changed, 106 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f517cbb..30cb10f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,11 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "dictionary-en": "^4.0.0", "express": "^5.1.0", "mammoth": "^1.12.0", - "multer": "^2.2.0" + "multer": "^2.2.0", + "nspell": "^2.1.5" }, "engines": { "node": ">=24" @@ -273,6 +275,16 @@ "node": ">= 0.8" } }, + "node_modules/dictionary-en": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/dictionary-en/-/dictionary-en-4.0.0.tgz", + "integrity": "sha512-3NHnE1uq33ZE/CIwaZ6gqxa4BnglHnxeAcTM0GJ7cmtRGcvX9InMK/IqLtYcUMFCUpUNgybH+DzkqdgAo3F1zg==", + "license": "(MIT AND BSD)", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/dingbat-to-unicode": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz", @@ -583,6 +595,29 @@ "node": ">= 0.10" } }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -783,6 +818,15 @@ "node": ">= 0.6" } }, + "node_modules/nspell": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/nspell/-/nspell-2.1.5.tgz", + "integrity": "sha512-PSStyugKMiD9mHmqI/CR5xXrSIGejUXPlo88FBRq5Og1kO5QwQ5Ilu8D8O5I/SHpoS+mibpw6uKA8rd3vXd2Sg==", + "license": "MIT", + "dependencies": { + "is-buffer": "^2.0.0" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", diff --git a/package.json b/package.json index f1dcb0d..d1f6ceb 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,11 @@ "author": "NateEmmert", "license": "ISC", "dependencies": { + "dictionary-en": "^4.0.0", "express": "^5.1.0", "mammoth": "^1.12.0", - "multer": "^2.2.0" + "multer": "^2.2.0", + "nspell": "^2.1.5" }, "engines": { "node": ">=24" diff --git a/public/app.js b/public/app.js index 8bd9831..ab96621 100644 --- a/public/app.js +++ b/public/app.js @@ -2519,6 +2519,37 @@ $('#btn-test').addEventListener('click', () => { startTest(); }); +$('#btn-freetype').addEventListener('click', () => { + backTarget = () => openKid(currentStudent.id, 'spelling'); + $('#freetype-feedback').innerHTML = ''; + $('#freetype-input').value = ''; + show('freetype'); + $('#freetype-input').focus(); +}); + +$('#freetype-form').addEventListener('submit', async (e) => { + e.preventDefault(); + const input = $('#freetype-input'); + const typed = input.value.trim(); + if (!typed) return; + const fb = $('#freetype-feedback'); + try { + const r = await api(`/api/spellcheck?word=${encodeURIComponent(typed)}`); + if (r.correct) { + fb.innerHTML = ``; + } else { + const tips = r.suggestions.length + ? ` Did you mean: ${r.suggestions.map((x) => `${esc(x)}`).join(', ')}?` + : ''; + fb.innerHTML = ``; + alert(`"${r.word}" is spelled wrong. Try again!`); + } + } catch (err) { + fb.innerHTML = ``; + } + input.select(); +}); + // ---------- docs (OnlyOffice) ---------- let docsEditorInstance = null; diff --git a/public/index.html b/public/index.html index d8c8d53..a080b58 100644 --- a/public/index.html +++ b/public/index.html @@ -99,6 +99,7 @@
+
@@ -273,6 +274,20 @@ + + +