Forum Discussion
Crossword in Rise
I vibe coded a crossword puzzle interaction in the new Articulate Rise custom html block to support our Accounts Review training.
It took about an hour of back-and-forth with Copilot to get this working.
Check it out here
Full HTML code is below the preview, feel free to adapt it and repurpose for own projects.
20 Replies
- TaraPCommunity Member
I absolutely love this! Thank you!
- CDawesCommunity Member
- CDawesCommunity Member
I'm not sure why the txt file won't stay attached.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Crossword</title>
<style>
:root {
--gap: 2px;
--ok: #c8f7c5;
--bad: #f7c5c5;
--blank: #eee;
--brand: #0079bf;
--cell-size: 40px;
--highlight: #fff9b3;
--focus-ring: #0079bf;
}
body { font-family: Segoe UI, Arial, sans-serif; margin: 0; padding: 20px; }
.cw-wrap { display:flex; align-items:flex-start; gap:20px; }
.controls { display:flex; gap:10px; margin-bottom:15px; flex-wrap:wrap; }
.controls button { padding:10px 16px; background:var(--brand); color:#fff; border:none; border-radius:6px; cursor:pointer; font-size:14px; font-weight:500; min-height:44px; transition:background .2s; }
.controls button.secondary { background:#666; }
.controls button:hover { background:#006aa8; }
.controls button.secondary:hover { background:#555; }
.controls button:focus { outline:3px solid var(--focus-ring); outline-offset:2px; }
.grid { display:grid; gap:var(--gap); justify-content:center; grid-template-columns: repeat(var(--cols), var(--cell-size)); }
.cell { width:var(--cell-size); height:var(--cell-size); background:#fff; border:1px solid #c9c9c9; display:flex; align-items:center; justify-content:center; position:relative; }
.blank { background:var(--blank); border-color:#d9d9d9; }
.cell-number { position:absolute; top:2px; left:3px; font-size:10px; font-weight:bold; color:#333; pointer-events:none; }
.cell input { font-size:calc(var(--cell-size)*0.6); text-transform:uppercase; text-align:center; width:100%; height:100%; border:none; outline:none; background:transparent; -moz-appearance:textfield; }
.cell input:focus { outline:3px solid var(--focus-ring); outline-offset:-3px; z-index:10; }
.ok::after { content:"✔"; color:green; font-size:.8em; position:absolute; bottom:2px; right:2px; }
.bad::after { content:"✖"; color:red; font-size:.8em; position:absolute; bottom:2px; right:2px; }
.highlight { background-color:var(--highlight); }
.highlight-active { background-color:#ffd700; }
.clues { max-width:380px; }
.clue-section { margin-bottom:20px; }
.clue-heading { padding:8px; background:var(--brand); color:#fff; border-radius:6px; font-size:1.1rem; margin-bottom:8px; font-weight:bold; }
.clue-section p { padding:8px 10px; margin:6px 0; cursor:pointer; border-radius:4px; transition:background .2s; min-height:44px; display:flex; align-items:center; }
.clue-section p.active-clue { background:var(--highlight); border-left:4px solid var(--brand); }
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }.modal { display:none; position:fixed; z-index:1000; inset:0; background:rgba(0,0,0,.5); }
.modal.show { display:flex; align-items:center; justify-content:center; }
.modal-content { background:#fff; padding:30px; border-radius:12px; max-width:420px; text-align:center; box-shadow:0 4px 20px rgba(0,0,0,.3); }MeDia (max-width:800px) {
.cw-wrap { flex-direction:column; align-items:center; }
.board, .clues { width:100%; max-width:95vw; }
.controls button { flex:1 1 calc(50% - 5px); min-width:120px; }
}body.high-contrast { --ok:#90ee90; --bad:#ffb3b3; --blank:#ddd; --highlight:#ffff00; --focus-ring:#000; }
body.high-contrast .cell { border:2px solid #000; }
body.high-contrast .cell input { color:#000; font-weight:bold; }
</style>
</head>
<body>
<div class="cw-wrap">
<div class="board">
<div class="controls">
<button id="checkBtn" aria-label="Check all answers">Check Answers</button>
<button id="clearWordBtn" class="secondary" aria-label="Clear current word">Clear Word</button>
<button id="clearAllBtn" class="secondary" aria-label="Clear all answers">Clear All</button>
<button id="revealLetterBtn" aria-label="Reveal current letter">Reveal Letter</button>
<button id="revealWordBtn" aria-label="Reveal current word">Reveal Word</button>
<button id="contrastBtn" class="secondary" aria-label="Toggle high contrast mode">High Contrast</button>
</div>
<div id="grid" class="grid" aria-label="Crossword grid" role="grid"></div>
</div><div class="clues">
<div class="clue-section">
<div class="clue-heading">Across</div>
<div id="acrossClues"></div>
</div>
<div class="clue-section">
<div class="clue-heading">Down</div>
<div id="downClues"></div>
</div>
</div>
</div><div id="completionModal" class="modal" role="dialog" aria-labelledby="modalTitle" aria-modal="true">
<div class="modal-content">
<h2 id="modalTitle">🎉 Congratulations!</h2>
<p>You've completed the crossword correctly!</p>
<button onclick="closeModal()">Close</button>
</div>
</div><div id="announcements" class="sr-only" aria-live="polite" aria-atomic="true"></div>
<script>
/* ===== Editable Word List ===== */
const wordList = [
{word:"APPLE", clue:"A type of fruit that is usually red or green"},
{word:"TRIGGER", clue:"What action occurs? When does it happen?"},
{word:"MATTER", clue:"Subject ________ Expert"},
{word:"LEARNERS", clue:"Use materials"},
{word:"SCHEDULE", clue:"What we need to follow"},
{word:"NOVEMBER", clue:"Election month"},
{word:"TUESDAY", clue:"Election day"},
{word:"RECHARGE", clue:"Weekends"},
{word:"STORYLINE", clue:"Can be extended with Javascript"},
{word:"ONLINE", clue:"__________ Learning"}
];/* ===== Generator ===== */
function generateCrossword(list){
const words = list.map(w=>({...w, word:w.word.toUpperCase()})).sort((a,b)=>b.word.length-a.word.length);
const placed = [];
const grid = {};
const first = words[0]; const sr=10, sc=10;
placed.push({word:first.word, clue:first.clue, r:sr, c:sc, dir:"across"});
for(let i=0;i<first.word.length;i++){ grid[`${sr},${sc+i}`] = {letter:first.word[i], words:[0]}; }for(let w=1; w<words.length; w++){
const word = words[w].word, clue = words[w].clue;
let best=null, maxI=0;
for(let p=0;p<placed.length;p++){
const pw=placed[p];
for(const dir of ["across","down"]){
if(dir===pw.dir) continue;
for(let i=0;i<word.length;i++){
for(let j=0;j<pw.word.length;j++){
if(word[i]!==pw.word[j]) continue;
let r,c;
if(dir==="across"){ r = pw.dir==="across"? pw.r : pw.r + j; c = pw.dir==="across"? pw.c + j - i : pw.c - i; }
else { r = pw.dir==="across"? pw.r - i : pw.r + j - i; c = pw.dir==="across"? pw.c + j : pw.c; }
if(isValid(word,r,c,dir,grid)){
const inter = countInter(word,r,c,dir,grid);
if(inter>maxI){ maxI=inter; best={r,c,dir}; }
}
}
}
}
}
if(best){
placed.push({word, clue, r:best.r, c:best.c, dir:best.dir});
for(let i=0;i<word.length;i++){
const rr = best.dir==="across" ? best.r : best.r + i;
const cc = best.dir==="across" ? best.c + i : best.c;
const key = `${rr},${cc}`;
if(!grid[key]) grid[key] = {letter:word[i], words:[]};
grid[key].words.push(placed.length-1);
}
}
}// Normalize to start at (1,1)
let minR=Infinity, minC=Infinity;
for(const key in grid){ const [r,c]=key.split(',').map(Number); minR=Math.min(minR,r); minC=Math.min(minC,c); }
placed.forEach(w=>{ w.r = w.r - minR + 1; w.c = w.c - minC + 1; });// Assign clue numbers by start cell order
const starts = {};
placed.forEach((w,idx)=>{ const k=`${w.r},${w.c}`; if(!starts[k]) starts[k]=[]; starts[k].push({idx,dir:w.dir}); });
const startKeys = Object.keys(starts).sort((a,b)=>{
const [r1,c1]=a.split(',').map(Number); const [r2,c2]=b.split(',').map(Number);
return r1===r2 ? c1-c2 : r1-r2;
});
let num=1;
startKeys.forEach(k=>{ starts[k].forEach(({idx})=> placed[idx].num=num); num++; });return placed;
}
function isValid(word,r,c,dir,g){
for(let i=0;i<word.length;i++){
const rr = dir==="across"? r : r + i;
const cc = dir==="across"? c + i : c;
const key = `${rr},${cc}`;
if(g[key] && g[key].letter !== word[i]) return false;
if(!g[key]){
const checks = dir==="across" ? [[rr-1,cc],[rr+1,cc]] : [[rr,cc-1],[rr,cc+1]];
for(const [cr,cc2] of checks){ if(g[`${cr},${cc2}`]) return false; }
}
}
const before = dir==="across"? `${r},${c-1}` : `${r-1},${c}`;
const after = dir==="across"? `${r},${c+word.length}` : `${r+word.length},${c}`;
if(g[before] || g[after]) return false;
return true;
}
function countInter(word,r,c,dir,g){
let n=0;
for(let i=0;i<word.length;i++){
const rr = dir==="across"? r : r + i;
const cc = dir==="across"? c + i : c;
const key = `${rr},${cc}`;
if(g[key] && g[key].letter===word[i]) n++;
}
return n;
}/* ===== Render & Layout ===== */
const words = generateCrossword(wordList).sort((a,b)=>a.num-b.num);
let rows=0, cols=0;
words.forEach(({r,c,dir,word})=>{
const endR = dir==="across" ? r : r + word.length - 1;
const endC = dir==="across" ? c + word.length - 1 : c;
rows = Math.max(rows, endR);
cols = Math.max(cols, endC);
});
const BLANK = "#";
const SOL = Array.from({length: rows*cols}, ()=>BLANK);
const idx = (r,c)=>(r-1)*cols+(c-1);
function place(r,c,dir,word){
word = word.toUpperCase();
for(let i=0;i<word.length;i++){
const rr = dir==="across" ? r : r + i;
const cc = dir==="across" ? c + i : c;
SOL[idx(rr,cc)] = word[i];
}
}
words.forEach(w=>place(w.r,w.c,w.dir,w.word));// Auto-bumped storage version based on layout + list
function computeVersion(){
try{
const data = JSON.stringify({rows,cols,sol:SOL.join(''), list:wordList.map(w=>w.word).join('|')});
let h=0; for(let i=0;i<data.length;i++){ h=((h<<5)-h)+data.charCodeAt(i); h|=0; }
return 'v'+Math.abs(h);
}catch(e){ return 'v0'; }
}
const APP_VERSION = computeVersion();
const STORAGE_KEYS = { progress:`crossword-progress-${APP_VERSION}`, contrast:'highContrast' };const gridEl = document.getElementById('grid');
document.documentElement.style.setProperty('--cols', cols);
if(gridEl) gridEl.style.setProperty('--cols', cols);let currentDirection = "across";
let currentWord = null;
let autoCheckEnabled = false;
/* ----- Responsive sizing (mobile-friendly) ----- */
function updateCellSize() {
// Leave some room for controls/clues
const verticalPadding = 260; // header/controls/modal margin
const horizontalPadding = 60; // padding/margins
const maxCell = 56; // cap desktop
const minCell = 24; // cap mobile
const availH = Math.max(200, (window.innerHeight || document.documentElement.clientHeight) - verticalPadding);
const availW = Math.max(200, (window.innerWidth || document.documentElement.clientWidth) - horizontalPadding);
const hSize = Math.floor(availH / rows);
const wSize = Math.floor(availW / cols);
const size = Math.max(minCell, Math.min(maxCell, Math.min(hSize, wSize)));
document.documentElement.style.setProperty('--cell-size', size + 'px');
}
updateCellSize();
window.addEventListener('resize', updateCellSize, {passive:true});
window.addEventListener('orientationchange', updateCellSize);/* ===== Clues ===== */
function getCellNumbers(){
const nums={};
words.forEach(w=>{ const k=`${w.r},${w.c}`; if(!nums[k] || nums[k] > w.num) nums[k]=w.num; });
return nums;
}
function renderClues(){
const acrossEl = document.getElementById('acrossClues');
const downEl = document.getElementById('downClues');
acrossEl.innerHTML = ''; downEl.innerHTML = '';
const across = words.filter(w=>w.dir==='across').sort((a,b)=>a.num-b.num);
const down = words.filter(w=>w.dir==='down').sort((a,b)=>a.num-b.num);
for(const w of across){
const p=document.createElement('p'); p.id=`clue-${w.dir}-${w.num}`;
p.innerHTML = `<b>${w.num}</b> – ${w.clue}`; p.tabIndex=0;
p.addEventListener('click',()=>focusWord(w));
p.addEventListener('keydown',e=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); focusWord(w); } });
acrossEl.appendChild(p);
}
for(const w of down){
const p=document.createElement('p'); p.id=`clue-${w.dir}-${w.num}`;
p.innerHTML = `<b>${w.num}</b> – ${w.clue}`; p.tabIndex=0;
p.addEventListener('click',()=>focusWord(w));
p.addEventListener('keydown',e=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); focusWord(w); } });
downEl.appendChild(p);
}
}/* ===== Grid Render ===== */
function render(){
gridEl.innerHTML='';
const cellNumbers = getCellNumbers();
for(let r=1;r<=rows;r++){
for(let c=1;c<=cols;c++){
const val = SOL[idx(r,c)];
const cell = document.createElement('div');
cell.className='cell'; cell.dataset.row=r; cell.dataset.col=c;
if(val===BLANK){
cell.classList.add('blank');
}else{
const key=`${r},${c}`;
if(cellNumbers[key]){
const span=document.createElement('span'); span.className='cell-number'; span.textContent=cellNumbers[key];
cell.appendChild(span);
}
const input=document.createElement('input'); input.type='text'; input.maxLength=1;
input.setAttribute('aria-label',`Row ${r}, Column ${c}`);
input.addEventListener('input', e=>handleInput(e,cell,r,c));
input.addEventListener('keydown', e=>handleKeyDown(e,cell,r,c));
input.addEventListener('focus', ()=>highlightWord(input));
cell.dataset.answer = val;
cell.appendChild(input);
}
gridEl.appendChild(cell);
}
}
loadProgress();
}/* ===== Helpers ===== */
function getWordCells(w){
const arr=[];
for(let i=0;i<w.word.length;i++){
const r = w.dir==="across" ? w.r : w.r + i;
const c = w.dir==="across" ? w.c + i : w.c;
arr.push({row:r,col:c});
}
return arr;
}
function getFirstEmptyInputInWord(w){
for(const pos of getWordCells(w)){
const el = gridEl.children[idx(pos.row,pos.col)];
const i = el && el.querySelector('input');
if(i && !i.value) return i;
}
return null;
}
function getStrictOrder(){ // Across then Down by number
const across = words.filter(w=>w.dir==='across').sort((a,b)=>a.num-b.num);
const down = words.filter(w=>w.dir==='down').sort((a,b)=>a.num-b.num);
return [...across, ...down];
}/* ===== Highlight & Focus ===== */
function highlightWord(input){
document.querySelectorAll('.cell').forEach(c=>c.classList.remove('highlight','highlight-active'));
document.querySelectorAll('.clue-section p').forEach(p=>p.classList.remove('active-clue'));
if(!input) return;
const cell = input.closest('.cell'); if(!cell) return;
const row = +cell.dataset.row, col = +cell.dataset.col;
const w = words.find(w=> (w.dir===currentDirection &&
((w.dir==='across' && w.r===row && col>=w.c && col<w.c+w.word.length) ||
(w.dir==='down' && w.c===col && row>=w.r && row<w.r+w.word.length)))) ||
words.find(w=> ((w.dir==='across' && w.r===row && col>=w.c && col<w.c+w.word.length) ||
(w.dir==='down' && w.c===col && row>=w.r && row<w.r+w.word.length)));
if(w){
currentWord=w; currentDirection=w.dir;
for(const pos of getWordCells(w)){
const el = gridEl.children[idx(pos.row,pos.col)];
el.classList.add('highlight');
if(pos.row===row && pos.col===col) el.classList.add('highlight-active');
}
const clueEl = document.getElementById(`clue-${w.dir}-${w.num}`);
if(clueEl) clueEl.classList.add('active-clue');
announce(`${w.dir==='across'?'Across':'Down'} ${w.num}: ${w.clue}`);
}
}
function focusWord(w){
currentWord=w; currentDirection=w.dir;
const first = gridEl.children[idx(w.r,w.c)]; const input = first && first.querySelector('input');
if(input){ input.focus(); highlightWord(input); }
}/* ===== Input & Navigation (2ms autoskip, intelligent next-word, stop at end) ===== */
let saveTimer=null;
function throttledSaveProgress(){ clearTimeout(saveTimer); saveTimer=setTimeout(()=>{ saveProgress(); saveTimer=null; },500); }function handleInput(e,cell,r,c){
const t=e.target.value.toUpperCase(); e.target.value=t;
if(autoCheckEnabled) paint(cell,t);
if(t){
const next = findNextEmptyCellInCurrentWord(r,c);
if(next){ setTimeout(()=>next.focus(),2); }
else{
// Move to first empty cell of the next word in strict Across→Down order; stop at end
if(currentWord){
const order = getStrictOrder();
const curIdx = order.indexOf(currentWord);
for(let k=curIdx+1; k<order.length; k++){
const i = getFirstEmptyInputInWord(order[k]);
if(i){ currentWord=order[k]; currentDirection=order[k].dir; setTimeout(()=>i.focus(),2); break; }
}
}
}
}
throttledSaveProgress();
}
function findNextEmptyCellInCurrentWord(r,c){
if(!currentWord) return null;
const cells = getWordCells(currentWord);
const i = cells.findIndex(p=>p.row===r && p.col===c);
if(i>=0){
for(let k=i+1;k<cells.length;k++){
const el = gridEl.children[idx(cells[k].row,cells[k].col)];
const inp = el && el.querySelector('input');
if(inp && !inp.value) return inp;
}
}
return null;
}function handleKeyDown(e,cell,r,c){
const inputs = Array.from(document.querySelectorAll('.cell input'));
const currentIndex = inputs.indexOf(e.target);
let nextIndex=null;
switch(e.key){
case "ArrowRight": nextIndex=currentIndex+1; currentDirection="across"; break;
case "ArrowLeft": nextIndex=currentIndex-1; currentDirection="across"; break;
case "ArrowDown": nextIndex=currentIndex+cols; currentDirection="down"; break;
case "ArrowUp": nextIndex=currentIndex-cols; currentDirection="down"; break;
case "Tab": return;
case " ":
e.preventDefault(); toggleDirection(); highlightWord(e.target); return;
case "Backspace":
if(!e.target.value && currentWord){
e.preventDefault();
const cells=getWordCells(currentWord);
const i=cells.findIndex(p=>p.row===r && p.col===c);
if(i>0){
const prev = gridEl.children[idx(cells[i-1].row,cells[i-1].col)].querySelector('input');
if(prev){ prev.value=''; prev.focus(); if(autoCheckEnabled) paint(prev.closest('.cell'),''); throttledSaveProgress(); }
}
}else{ setTimeout(()=>throttledSaveProgress(),0); }
return;
case "Home":
e.preventDefault(); if(currentWord){ const first=gridEl.children[idx(currentWord.r,currentWord.c)].querySelector('input'); if(first) first.focus(); } return;
case "End":
e.preventDefault(); if(currentWord){ const lr=currentWord.dir==="across"? currentWord.r : currentWord.r+currentWord.word.length-1; const lc=currentWord.dir==="across"? currentWord.c+currentWord.word.length-1 : currentWord.c; const last=gridEl.children[idx(lr,lc)].querySelector('input'); if(last) last.focus(); } return;
}
if(nextIndex!==null && inputs[nextIndex]){ e.preventDefault(); inputs[nextIndex].focus(); }
}
function toggleDirection(){ currentDirection = currentDirection==="across" ? "down" : "across"; announce(`Direction: ${currentDirection}`); }/* ===== Checking & Modal ===== */
function paint(cell,val){
cell.classList.remove('ok','bad');
if(!val) return;
if(val===cell.dataset.answer){ cell.classList.add('ok'); announce('Correct'); }
else{ cell.classList.add('bad'); announce('Incorrect'); }
}
function checkAllAnswers(){
autoCheckEnabled = true;
const cells = gridEl.querySelectorAll('.cell:not(.blank)');
let allCorrect = true;
cells.forEach(cell=>{
const ans = cell.dataset.answer;
const input = cell.querySelector('input');
const val = (input && input.value ? input.value.toUpperCase() : "");
cell.classList.remove('ok','bad');
if(val === ans){
cell.classList.add('ok');
} else {
cell.classList.add('bad');
allCorrect = false;
}
});
if(allCorrect) showCompletionModal(); else announce("Some answers are incorrect. Incorrect cells are marked.");
}
function showCompletionModal(){ document.getElementById('completionModal').classList.add('show'); }
function closeModal(){ document.getElementById('completionModal').classList.remove('show'); }/* ===== Clear / Reveal ===== */
function clearCurrentWord(){
if(!currentWord){ announce("No word selected"); return; }
for(const pos of getWordCells(currentWord)){
const cell = gridEl.children[idx(pos.row,pos.col)];
const i = cell.querySelector('input');
if(i){ i.value=''; cell.classList.remove('ok','bad'); }
}
announce(`Cleared ${currentWord.dir} ${currentWord.num}`);
throttledSaveProgress();
}
function clearAll(){
// Clear everything without a confirm to avoid mobile popup issues
const inputs = gridEl.querySelectorAll('.cell input');
inputs.forEach(i=>{ i.value=''; i.closest('.cell').classList.remove('ok','bad'); });
announce("All answers cleared");
try{ localStorage.removeItem(STORAGE_KEYS.progress); }catch(e){}
}
function revealLetter(){
let target=document.activeElement;
if(!target || target.tagName!=='INPUT'){
const active=document.querySelector('.cell.highlight-active input');
if(active) target=active;
}
if(target){
const cell=target.closest('.cell');
if(cell && cell.dataset.answer){
target.value=cell.dataset.answer;
cell.classList.remove('bad'); cell.classList.add('ok');
announce(`Revealed letter: ${cell.dataset.answer}`);
throttledSaveProgress();
const r=+cell.dataset.row, c=+cell.dataset.col;
const next=findNextEmptyCellInCurrentWord(r,c);
if(next){ setTimeout(()=>next.focus(),2); }
else if(currentWord){
const order=getStrictOrder(); const curIdx=order.indexOf(currentWord);
for(let k=curIdx+1;k<order.length;k++){
const i=getFirstEmptyInputInWord(order[k]);
if(i){ currentWord=order[k]; currentDirection=order[k].dir; setTimeout(()=>i.focus(),2); break; }
}
}
}
} else { announce("Focus on a cell first"); }
}
function revealWord(){
if(!currentWord){ announce("No word selected"); return; }
for(const pos of getWordCells(currentWord)){
const cell = gridEl.children[idx(pos.row,pos.col)];
const i = cell.querySelector('input');
if(i){ i.value=cell.dataset.answer; cell.classList.remove('bad'); cell.classList.add('ok'); }
}
announce(`Revealed ${currentWord.dir} ${currentWord.num}: ${currentWord.word}`);
throttledSaveProgress();
// Move to first empty of next word (strict order); stop at end
const order=getStrictOrder(); const curIdx=order.indexOf(currentWord);
for(let k=curIdx+1;k<order.length;k++){
const i=getFirstEmptyInputInWord(order[k]);
if(i){ currentWord=order[k]; currentDirection=order[k].dir; setTimeout(()=>i.focus(),2); break; }
}
}/* ===== Persistence ===== */
function saveProgress(){
try{
const progress={};
const inputs=gridEl.querySelectorAll('.cell input');
inputs.forEach((i,k)=>{ if(i.value) progress[k]=i.value; });
localStorage.setItem(STORAGE_KEYS.progress, JSON.stringify(progress));
}catch(e){ console.log('Could not save progress', e); }
}
function loadProgress(){
try{
const data = localStorage.getItem(STORAGE_KEYS.progress);
if(data){
const progress=JSON.parse(data);
const inputs=gridEl.querySelectorAll('.cell input');
inputs.forEach((i,k)=>{ if(progress && progress[k]) i.value=progress[k]; });
}
if(localStorage.getItem('highContrast')==='true') document.body.classList.add('high-contrast');
}catch(e){ console.log('Could not load progress', e); }
}/* ===== High Contrast ===== */
function toggleHighContrast(){
document.body.classList.toggle('high-contrast');
try{ localStorage.setItem('highContrast', document.body.classList.contains('high-contrast') ? 'true' : 'false'); }catch(e){}
}/* ===== Announce ===== */
function announce(m){ document.getElementById('announcements').textContent = m; }/* ===== Wire up ===== */
document.getElementById('checkBtn').onclick = checkAllAnswers;
document.getElementById('clearWordBtn').onclick = clearCurrentWord;
document.getElementById('clearAllBtn').onclick = clearAll;
document.getElementById('revealLetterBtn').onclick = revealLetter;
document.getElementById('revealWordBtn').onclick = revealWord;
document.getElementById('contrastBtn').onclick = toggleHighContrast;
window.onclick = e => { const m=document.getElementById('completionModal'); if(e.target===m) closeModal(); };/* ===== Init ===== */
renderClues();
render();
announce('Crossword ready — '+APP_VERSION);
</script>
</body>
</html>- ShaneMurphy-8f6Community Member
I really like this version, thank you very much.
- samlnolanCommunity Member
Such a cool concept! Can anyone help troubleshoot why the code is not working? I havent been able to find a solution
- Deleted user
Thanks samlnolan - I think it was an error on my part when I pasted the code, I've redone it now and tested - it should work now if you give it a refresh?
- samlnolanCommunity Member
It works now! Thank you so much
- CandiceMCCommunity Member
This is awesome! It worked for me, spent a bit more time making minor adjustments to the code. And once you have it set up to your liking, it is pretty simple to update with for a weekly/monthly crossword challenge!
- EmiliaPietrz889Community Member
Hey, CandiceMC did you edit the code with AI or yourself? I really like how it worked out for you, but coding is totally not my thing - YET. Is it ok for me to ask if you would be able to catch up and briefly explain? Or give me some advice in the comment if it's ok.
- CandiceMCCommunity Member
EmiliaPietrz229 Used copilot. I gave it the initial code in the example and took multiple attempts to fix it the way I wanted. Once the basic coding was done, I was able to review it and figure out how to make my own edits to identify columns and rows to make edits for different version of the crossword puzzle. I am open for a quick chat to explain my process. cybersafemindset@gmail.com
- DavidAtkinson-dCommunity Member
This is very good, we are starting to see the potential of the new custom block / code feature in rise. As above comment the copied code fails - I am thinking there is a source image or similar linked
- Deleted user
Thanks DavidAtkinson-d - I think it was an error on my part when I pasted the code, I've redone it now and tested - it should work now if you give it a refresh?
- JanessaBaddeleyCommunity Member
This is a good idea! The code isn't working when I copy it into my course though.
- Deleted user
Thanks JanessaBaddeley - I think it was an error on my part when I pasted the code, I've redone it now and tested - it should work now if you give it a refresh?
- AG001Community Member
It works now Thanks.
- LisaAnderson-57Community Member
This is fantastic! Thank you for sharing.
Have you, or anyone for that matter, tested this for accessibility accommodations - ADA?
Thank you!
- Deleted user
Hi LisaAnderson-57
I have made a new version with improvements for accessibility accommodations - if you open it again and scroll down you can find the new version and full code.
- EmilyFrisbyCommunity Member
I love this idea! Thanks for sharing Daniel 😀
I'm so glad to see you shared this here Deleted user! Just a heads-up: we’ll be featuring this in an upcoming ELH Weekly newsletter. Be sure you’re subscribed if you want to get it in your inbox. 🎉
This is so fun to see! Thanks for sharing. Love the idea.
FYI we've also added a "Copy code" button to code snippets (Block Library ->Multimedia -> Code Snippet) if that makes it easier for you to share examples with others!
Related Content
- 7 months ago
- 5 months ago
- 1 year ago
- 17 days ago