tablet-initial-release
This commit is contained in:
657
public/tablet-app.js
Normal file
657
public/tablet-app.js
Normal file
@@ -0,0 +1,657 @@
|
||||
// Full-Featured Tablet Crossword App
|
||||
class TabletCrosswordApp {
|
||||
constructor() {
|
||||
this.currentLevel = 1
|
||||
this.coins = 100
|
||||
this.hints = 3
|
||||
this.currentPuzzle = null
|
||||
this.userAnswers = {}
|
||||
this.selectedCell = null
|
||||
this.selectedWord = null
|
||||
this.gridElement = document.getElementById('crosswordGrid')
|
||||
this.cells = []
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
||||
init() {
|
||||
this.loadGameState()
|
||||
this.loadPuzzle(this.currentLevel)
|
||||
this.setupEventListeners()
|
||||
this.updateUI()
|
||||
this.enableFullscreen()
|
||||
}
|
||||
|
||||
enableFullscreen() {
|
||||
// Request fullscreen on first interaction
|
||||
document.addEventListener('click', () => {
|
||||
if (document.documentElement.requestFullscreen && !document.fullscreenElement) {
|
||||
document.documentElement.requestFullscreen().catch(() => {})
|
||||
}
|
||||
}, { once: true })
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
// Menu
|
||||
document.getElementById('menuBtn').addEventListener('click', () => {
|
||||
document.getElementById('sideMenu').classList.add('active')
|
||||
})
|
||||
document.getElementById('closeMenu').addEventListener('click', () => {
|
||||
document.getElementById('sideMenu').classList.remove('active')
|
||||
})
|
||||
|
||||
// On-screen keyboard
|
||||
document.querySelectorAll('.key-btn').forEach(btn => {
|
||||
if (!btn.id) {
|
||||
btn.addEventListener('click', () => {
|
||||
const letter = btn.textContent.trim()
|
||||
this.handleLetterInput(letter)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById('delKey').addEventListener('click', () => this.handleDelete())
|
||||
document.getElementById('hintKey').addEventListener('click', () => this.useHintForCurrentWord())
|
||||
|
||||
// Actions
|
||||
document.getElementById('checkBtn').addEventListener('click', () => this.checkAllAnswers())
|
||||
document.getElementById('clearBtn').addEventListener('click', () => this.clearGrid())
|
||||
|
||||
// Menu items
|
||||
document.getElementById('newGame').addEventListener('click', () => this.newGame())
|
||||
document.getElementById('dailyPuzzle').addEventListener('click', () => {
|
||||
this.showToast('Dagelijkse puzzel komt binnenkort!')
|
||||
document.getElementById('sideMenu').classList.remove('active')
|
||||
})
|
||||
document.getElementById('levelSelect').addEventListener('click', () => {
|
||||
this.showToast('Niveau selectie komt binnenkort!')
|
||||
document.getElementById('sideMenu').classList.remove('active')
|
||||
})
|
||||
|
||||
document.getElementById('nextBtn').addEventListener('click', () => this.nextPuzzle())
|
||||
|
||||
// Prevent accidental zoom/scroll
|
||||
document.addEventListener('gesturestart', e => e.preventDefault())
|
||||
document.addEventListener('gesturechange', e => e.preventDefault())
|
||||
}
|
||||
|
||||
loadPuzzle(level) {
|
||||
if (typeof DUTCH_PUZZLES !== 'undefined') {
|
||||
this.currentPuzzle = DUTCH_PUZZLES[`level${level}`] || DUTCH_PUZZLES.level1
|
||||
}
|
||||
|
||||
this.renderGrid()
|
||||
this.updateProgress()
|
||||
this.updateUI()
|
||||
}
|
||||
|
||||
renderGrid() {
|
||||
if (!this.currentPuzzle) return
|
||||
|
||||
const grid = this.currentPuzzle.grid
|
||||
const words = this.currentPuzzle.words
|
||||
|
||||
this.gridElement.innerHTML = ''
|
||||
this.cells = []
|
||||
|
||||
const rows = grid.length
|
||||
const cols = Math.max(...grid.map(row => row.length)) + 1
|
||||
const cellSize = this.calculateCellSize(rows, cols)
|
||||
|
||||
this.gridElement.style.gridTemplateColumns = `repeat(${cols}, ${cellSize}px)`
|
||||
this.gridElement.style.gridTemplateRows = `repeat(${rows}, ${cellSize}px)`
|
||||
|
||||
// Create cells
|
||||
for (let row = 0; row < rows; row++) {
|
||||
for (let col = 0; col < cols; col++) {
|
||||
if (col === 0) {
|
||||
const clueData = this.getClueForRow(row, words)
|
||||
this.gridElement.appendChild(this.createClueCell(clueData, cellSize))
|
||||
} else {
|
||||
const gridCol = col - 1
|
||||
const cellValue = grid[row]?.[gridCol] || '#'
|
||||
const cell = this.createCell(cellValue, row, gridCol, words, cellSize)
|
||||
this.gridElement.appendChild(cell)
|
||||
|
||||
if (cell.classList.contains('letter-cell')) {
|
||||
this.cells.push({ element: cell, row, col: gridCol })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calculateCellSize(rows, cols) {
|
||||
const headerHeight = 66
|
||||
const progressHeight = 40
|
||||
const keyboardHeight = 230
|
||||
const padding = 30
|
||||
|
||||
const availableHeight = window.innerHeight - headerHeight - progressHeight - keyboardHeight - padding
|
||||
const availableWidth = window.innerWidth - padding
|
||||
|
||||
const maxFromHeight = Math.floor(availableHeight / rows)
|
||||
const maxFromWidth = Math.floor(availableWidth / cols)
|
||||
|
||||
let cellSize = Math.min(maxFromHeight, maxFromWidth)
|
||||
cellSize = Math.max(50, Math.min(75, cellSize))
|
||||
|
||||
return cellSize
|
||||
}
|
||||
|
||||
getClueForRow(row, words) {
|
||||
return words.find(w => w.direction === 'horizontal' && w.startRow === row)
|
||||
}
|
||||
|
||||
createClueCell(clueData, cellSize) {
|
||||
const cell = document.createElement('div')
|
||||
cell.className = 'grid-cell clue-cell'
|
||||
cell.style.width = `${cellSize}px`
|
||||
cell.style.height = `${cellSize}px`
|
||||
|
||||
if (clueData) {
|
||||
const text = document.createElement('div')
|
||||
text.className = 'clue-text'
|
||||
text.textContent = clueData.clue
|
||||
|
||||
const arrow = document.createElement('div')
|
||||
arrow.className = 'arrow'
|
||||
arrow.textContent = '→'
|
||||
|
||||
cell.appendChild(text)
|
||||
cell.appendChild(arrow)
|
||||
} else {
|
||||
cell.classList.add('blocked-cell')
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
createCell(value, row, col, words, cellSize) {
|
||||
const cell = document.createElement('div')
|
||||
cell.className = 'grid-cell'
|
||||
cell.style.width = `${cellSize}px`
|
||||
cell.style.height = `${cellSize}px`
|
||||
cell.dataset.row = row
|
||||
cell.dataset.col = col
|
||||
|
||||
if (value === '#') {
|
||||
const clueData = this.getClueAtPosition(row, col, words)
|
||||
if (clueData) {
|
||||
cell.classList.add('clue-cell')
|
||||
const text = document.createElement('div')
|
||||
text.className = 'clue-text'
|
||||
text.textContent = clueData.clue
|
||||
const arrow = document.createElement('div')
|
||||
arrow.className = 'arrow'
|
||||
arrow.textContent = '→'
|
||||
cell.appendChild(text)
|
||||
cell.appendChild(arrow)
|
||||
} else {
|
||||
cell.classList.add('blocked-cell')
|
||||
}
|
||||
} else {
|
||||
cell.classList.add('letter-cell')
|
||||
const key = `${row}-${col}`
|
||||
cell.textContent = this.userAnswers[key] || ''
|
||||
|
||||
// Click to select and highlight word
|
||||
cell.addEventListener('click', () => {
|
||||
this.selectCell(cell, row, col)
|
||||
this.highlightWord(row, col)
|
||||
})
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
getClueAtPosition(row, col, words) {
|
||||
for (const word of words) {
|
||||
if (word.direction === 'horizontal' && word.startRow === row && word.startCol - 1 === col) {
|
||||
return word
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
selectCell(cell, row, col) {
|
||||
this.cells.forEach(c => c.element.classList.remove('active'))
|
||||
cell.classList.add('active')
|
||||
this.selectedCell = { element: cell, row, col }
|
||||
}
|
||||
|
||||
highlightWord(row, col) {
|
||||
// Clear previous highlights
|
||||
this.cells.forEach(c => c.element.classList.remove('highlighted'))
|
||||
|
||||
// Find word containing this cell
|
||||
const word = this.findWordContainingCell(row, col)
|
||||
if (!word) return
|
||||
|
||||
this.selectedWord = word
|
||||
|
||||
// Highlight all cells in this word
|
||||
if (word.direction === 'horizontal') {
|
||||
for (let c = word.startCol; c < word.startCol + word.answer.length; c++) {
|
||||
const cellData = this.cells.find(cell => cell.row === word.startRow && cell.col === c)
|
||||
if (cellData) {
|
||||
cellData.element.classList.add('highlighted')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let r = word.startRow; r < word.startRow + word.answer.length; r++) {
|
||||
const cellData = this.cells.find(cell => cell.row === r && cell.col === word.startCol)
|
||||
if (cellData) {
|
||||
cellData.element.classList.add('highlighted')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
findWordContainingCell(row, col) {
|
||||
for (const word of this.currentPuzzle.words) {
|
||||
if (word.direction === 'horizontal') {
|
||||
if (word.startRow === row && col >= word.startCol && col < word.startCol + word.answer.length) {
|
||||
return word
|
||||
}
|
||||
} else if (word.direction === 'vertical') {
|
||||
if (word.startCol === col && row >= word.startRow && row < word.startRow + word.answer.length) {
|
||||
return word
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
handleLetterInput(letter) {
|
||||
if (!this.selectedCell) {
|
||||
// Auto-select first empty cell
|
||||
const firstEmpty = this.cells.find(c => !c.element.textContent)
|
||||
if (firstEmpty) {
|
||||
this.selectCell(firstEmpty.element, firstEmpty.row, firstEmpty.col)
|
||||
this.highlightWord(firstEmpty.row, firstEmpty.col)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const { element, row, col } = this.selectedCell
|
||||
element.textContent = letter
|
||||
const key = `${row}-${col}`
|
||||
this.userAnswers[key] = letter
|
||||
|
||||
this.saveGameState()
|
||||
this.updateProgress()
|
||||
|
||||
// Check if word is complete
|
||||
this.checkWordComplete()
|
||||
|
||||
// Move to next cell in word
|
||||
this.moveToNextInWord()
|
||||
}
|
||||
|
||||
handleDelete() {
|
||||
if (!this.selectedCell) return
|
||||
|
||||
const { element, row, col } = this.selectedCell
|
||||
|
||||
if (element.textContent) {
|
||||
// Delete current cell
|
||||
element.textContent = ''
|
||||
const key = `${row}-${col}`
|
||||
delete this.userAnswers[key]
|
||||
element.classList.remove('correct', 'incorrect')
|
||||
} else {
|
||||
// Move to previous cell and delete
|
||||
this.moveToPreviousInWord()
|
||||
if (this.selectedCell) {
|
||||
const { element: prevElement, row: prevRow, col: prevCol } = this.selectedCell
|
||||
prevElement.textContent = ''
|
||||
const key = `${prevRow}-${prevCol}`
|
||||
delete this.userAnswers[key]
|
||||
prevElement.classList.remove('correct', 'incorrect')
|
||||
}
|
||||
}
|
||||
|
||||
this.saveGameState()
|
||||
this.updateProgress()
|
||||
}
|
||||
|
||||
moveToNextInWord() {
|
||||
if (!this.selectedCell || !this.selectedWord) return
|
||||
|
||||
const { row, col } = this.selectedCell
|
||||
const word = this.selectedWord
|
||||
|
||||
let nextRow = row
|
||||
let nextCol = col
|
||||
|
||||
if (word.direction === 'horizontal') {
|
||||
nextCol++
|
||||
if (nextCol >= word.startCol + word.answer.length) return
|
||||
} else {
|
||||
nextRow++
|
||||
if (nextRow >= word.startRow + word.answer.length) return
|
||||
}
|
||||
|
||||
const nextCell = this.cells.find(c => c.row === nextRow && c.col === nextCol)
|
||||
if (nextCell) {
|
||||
this.selectCell(nextCell.element, nextCell.row, nextCell.col)
|
||||
}
|
||||
}
|
||||
|
||||
moveToPreviousInWord() {
|
||||
if (!this.selectedCell || !this.selectedWord) return
|
||||
|
||||
const { row, col } = this.selectedCell
|
||||
const word = this.selectedWord
|
||||
|
||||
let prevRow = row
|
||||
let prevCol = col
|
||||
|
||||
if (word.direction === 'horizontal') {
|
||||
prevCol--
|
||||
if (prevCol < word.startCol) return
|
||||
} else {
|
||||
prevRow--
|
||||
if (prevRow < word.startRow) return
|
||||
}
|
||||
|
||||
const prevCell = this.cells.find(c => c.row === prevRow && c.col === prevCol)
|
||||
if (prevCell) {
|
||||
this.selectCell(prevCell.element, prevCell.row, prevCell.col)
|
||||
}
|
||||
}
|
||||
|
||||
checkWordComplete() {
|
||||
if (!this.selectedWord) return
|
||||
|
||||
const word = this.selectedWord
|
||||
let userWord = ''
|
||||
let allFilled = true
|
||||
|
||||
if (word.direction === 'horizontal') {
|
||||
for (let c = word.startCol; c < word.startCol + word.answer.length; c++) {
|
||||
const key = `${word.startRow}-${c}`
|
||||
const letter = this.userAnswers[key]
|
||||
if (!letter) {
|
||||
allFilled = false
|
||||
break
|
||||
}
|
||||
userWord += letter
|
||||
}
|
||||
} else {
|
||||
for (let r = word.startRow; r < word.startRow + word.answer.length; r++) {
|
||||
const key = `${r}-${word.startCol}`
|
||||
const letter = this.userAnswers[key]
|
||||
if (!letter) {
|
||||
allFilled = false
|
||||
break
|
||||
}
|
||||
userWord += letter
|
||||
}
|
||||
}
|
||||
|
||||
if (allFilled) {
|
||||
// Auto-validate word
|
||||
if (userWord === word.answer) {
|
||||
this.animateWordSuccess(word)
|
||||
} else {
|
||||
this.animateWordError(word)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animateWordSuccess(word) {
|
||||
const cells = []
|
||||
|
||||
if (word.direction === 'horizontal') {
|
||||
for (let c = word.startCol; c < word.startCol + word.answer.length; c++) {
|
||||
const cellData = this.cells.find(cell => cell.row === word.startRow && cell.col === c)
|
||||
if (cellData) cells.push(cellData.element)
|
||||
}
|
||||
} else {
|
||||
for (let r = word.startRow; r < word.startRow + word.answer.length; r++) {
|
||||
const cellData = this.cells.find(cell => cell.row === r && cell.col === word.startCol)
|
||||
if (cellData) cells.push(cellData.element)
|
||||
}
|
||||
}
|
||||
|
||||
cells.forEach((cell, index) => {
|
||||
setTimeout(() => {
|
||||
cell.classList.remove('incorrect', 'highlighted')
|
||||
cell.classList.add('correct', 'word-complete')
|
||||
|
||||
setTimeout(() => {
|
||||
cell.classList.remove('word-complete')
|
||||
}, 800)
|
||||
}, index * 100)
|
||||
})
|
||||
|
||||
this.showToast('Correct! 🎉')
|
||||
this.checkPuzzleComplete()
|
||||
}
|
||||
|
||||
animateWordError(word) {
|
||||
const cells = []
|
||||
|
||||
if (word.direction === 'horizontal') {
|
||||
for (let c = word.startCol; c < word.startCol + word.answer.length; c++) {
|
||||
const cellData = this.cells.find(cell => cell.row === word.startRow && cell.col === c)
|
||||
if (cellData) cells.push(cellData.element)
|
||||
}
|
||||
} else {
|
||||
for (let r = word.startRow; r < word.startRow + word.answer.length; r++) {
|
||||
const cellData = this.cells.find(cell => cell.row === r && cell.col === word.startCol)
|
||||
if (cellData) cells.push(cellData.element)
|
||||
}
|
||||
}
|
||||
|
||||
cells.forEach(cell => {
|
||||
cell.classList.remove('correct')
|
||||
cell.classList.add('incorrect')
|
||||
|
||||
setTimeout(() => {
|
||||
cell.classList.remove('incorrect')
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
this.showToast('Probeer opnieuw')
|
||||
}
|
||||
|
||||
checkPuzzleComplete() {
|
||||
const allCorrect = this.cells.every(cell => {
|
||||
const row = cell.row
|
||||
const col = cell.col
|
||||
const key = `${row}-${col}`
|
||||
const userAnswer = this.userAnswers[key]
|
||||
const correctAnswer = this.getCorrectAnswer(row, col)
|
||||
return userAnswer === correctAnswer
|
||||
})
|
||||
|
||||
if (allCorrect) {
|
||||
setTimeout(() => this.showSuccess(), 500)
|
||||
}
|
||||
}
|
||||
|
||||
checkAllAnswers() {
|
||||
this.cells.forEach(cell => {
|
||||
const row = cell.row
|
||||
const col = cell.col
|
||||
const key = `${row}-${col}`
|
||||
const userAnswer = this.userAnswers[key]
|
||||
const correctAnswer = this.getCorrectAnswer(row, col)
|
||||
|
||||
if (userAnswer === correctAnswer) {
|
||||
cell.element.classList.add('correct')
|
||||
cell.element.classList.remove('incorrect')
|
||||
} else if (userAnswer) {
|
||||
cell.element.classList.add('incorrect')
|
||||
cell.element.classList.remove('correct')
|
||||
}
|
||||
})
|
||||
|
||||
this.checkPuzzleComplete()
|
||||
}
|
||||
|
||||
getCorrectAnswer(row, col) {
|
||||
for (const word of this.currentPuzzle.words) {
|
||||
if (word.direction === 'horizontal') {
|
||||
if (word.startRow === row && col >= word.startCol && col < word.startCol + word.answer.length) {
|
||||
return word.answer[col - word.startCol]
|
||||
}
|
||||
} else if (word.direction === 'vertical') {
|
||||
if (word.startCol === col && row >= word.startRow && row < word.startRow + word.answer.length) {
|
||||
return word.answer[row - word.startRow]
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
useHintForCurrentWord() {
|
||||
if (this.hints <= 0) {
|
||||
this.showToast('Geen hints meer!')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.selectedWord) {
|
||||
this.showToast('Selecteer eerst een woord')
|
||||
return
|
||||
}
|
||||
|
||||
const word = this.selectedWord
|
||||
const emptyCells = []
|
||||
|
||||
if (word.direction === 'horizontal') {
|
||||
for (let c = word.startCol; c < word.startCol + word.answer.length; c++) {
|
||||
const key = `${word.startRow}-${c}`
|
||||
if (!this.userAnswers[key]) {
|
||||
emptyCells.push({ row: word.startRow, col: c, letter: word.answer[c - word.startCol] })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let r = word.startRow; r < word.startRow + word.answer.length; r++) {
|
||||
const key = `${r}-${word.startCol}`
|
||||
if (!this.userAnswers[key]) {
|
||||
emptyCells.push({ row: r, col: word.startCol, letter: word.answer[r - word.startRow] })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyCells.length === 0) {
|
||||
this.showToast('Woord al compleet!')
|
||||
return
|
||||
}
|
||||
|
||||
const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)]
|
||||
const key = `${randomCell.row}-${randomCell.col}`
|
||||
this.userAnswers[key] = randomCell.letter
|
||||
|
||||
const cellData = this.cells.find(c => c.row === randomCell.row && c.col === randomCell.col)
|
||||
if (cellData) {
|
||||
cellData.element.textContent = randomCell.letter
|
||||
}
|
||||
|
||||
this.hints--
|
||||
this.updateUI()
|
||||
this.saveGameState()
|
||||
this.showToast('Hint gebruikt!')
|
||||
this.checkWordComplete()
|
||||
}
|
||||
|
||||
clearGrid() {
|
||||
if (confirm('Alles wissen?')) {
|
||||
this.userAnswers = {}
|
||||
this.cells.forEach(cell => {
|
||||
cell.element.textContent = ''
|
||||
cell.element.classList.remove('correct', 'incorrect', 'highlighted')
|
||||
})
|
||||
this.saveGameState()
|
||||
this.updateProgress()
|
||||
this.showToast('Gewist')
|
||||
}
|
||||
}
|
||||
|
||||
newGame() {
|
||||
if (confirm('Nieuw spel starten?')) {
|
||||
this.currentLevel = 1
|
||||
this.userAnswers = {}
|
||||
this.loadPuzzle(1)
|
||||
this.saveGameState()
|
||||
document.getElementById('sideMenu').classList.remove('active')
|
||||
this.showToast('Nieuw spel gestart!')
|
||||
}
|
||||
}
|
||||
|
||||
showSuccess() {
|
||||
this.coins += 50
|
||||
this.hints += 1
|
||||
this.updateUI()
|
||||
this.saveGameState()
|
||||
document.getElementById('successModal').classList.add('active')
|
||||
}
|
||||
|
||||
nextPuzzle() {
|
||||
document.getElementById('successModal').classList.remove('active')
|
||||
this.currentLevel++
|
||||
this.userAnswers = {}
|
||||
this.loadPuzzle(this.currentLevel)
|
||||
this.saveGameState()
|
||||
this.showToast(`Niveau ${this.currentLevel}`)
|
||||
}
|
||||
|
||||
updateProgress() {
|
||||
const total = this.cells.length
|
||||
const filled = Object.keys(this.userAnswers).length
|
||||
const progress = total > 0 ? Math.round((filled / total) * 100) : 0
|
||||
|
||||
document.getElementById('progressFill').style.width = `${progress}%`
|
||||
document.getElementById('progressText').textContent = `${progress}%`
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
document.getElementById('coinsCount').textContent = this.coins
|
||||
document.getElementById('hintsCount').textContent = this.hints
|
||||
document.getElementById('levelNum').textContent = this.currentLevel
|
||||
}
|
||||
|
||||
showToast(message) {
|
||||
const toast = document.createElement('div')
|
||||
toast.className = 'toast'
|
||||
toast.textContent = message
|
||||
document.body.appendChild(toast)
|
||||
|
||||
setTimeout(() => {
|
||||
toast.remove()
|
||||
}, 2500)
|
||||
}
|
||||
|
||||
// LocalStorage - Game State Persistence
|
||||
saveGameState() {
|
||||
const state = {
|
||||
currentLevel: this.currentLevel,
|
||||
coins: this.coins,
|
||||
hints: this.hints,
|
||||
userAnswers: this.userAnswers,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
localStorage.setItem('crosswordGameState', JSON.stringify(state))
|
||||
}
|
||||
|
||||
loadGameState() {
|
||||
const saved = localStorage.getItem('crosswordGameState')
|
||||
if (saved) {
|
||||
const state = JSON.parse(saved)
|
||||
this.currentLevel = state.currentLevel || 1
|
||||
this.coins = state.coins || 100
|
||||
this.hints = state.hints || 3
|
||||
this.userAnswers = state.userAnswers || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new TabletCrosswordApp()
|
||||
})
|
||||
Reference in New Issue
Block a user