// Input handlers document .querySelector('#move-input') .addEventListener('change', (event) => assignCommands('backward', 'forward', event) ) document .querySelector('#rotate-input') .addEventListener('change', (event) => assignCommands('left', 'right', event) ) // Buttons handlers for (const button of document .querySelector('#touch-controls') .querySelectorAll('button')) { button.addEventListener('click', () => { const { command, value } = button.dataset // Check datas are set for button if (command === undefined || value === undefined) { alert( `Pas de command ou de valeur assigné au bouton "${button.title}"` ) throw new Error(`no command or value assigned to ${button.title}`) } // Check command is valid if ( !['forward', 'backward', 'left', 'right', 'stop'].includes(command) ) { alert( `La command "${command}" n'est pas valide en tant que ('forward', 'backward', 'left', 'right', 'stop')` ) throw new Error( `specified command "${command}" is not in ['forward', 'backward', 'left', 'right', 'stop']` ) } // Check value is valid finite number if (!Number.isFinite(Number(value))) { alert(`La valeur "${value}" n'est convertible en entier fini`) throw new Error( `value "${value}" cannot be casted to finite integer` ) } sendCommand(command, Number(value)) }) } // Keyboard handler document.addEventListener('keydown', ({ code }) => { if (code === 'ArrowUp') { return sendCommand('forward', 2) } if (code === 'ArrowDown') { return sendCommand('backward', 2) } if (code === 'ArrowLeft') { return sendCommand('left', 5) } if (code === 'ArrowRight') { return sendCommand('right', 5) } if (code === 'Space') { return sendCommand('stop', 0) } }) // Settings handler document .querySelector('#settings') .addEventListener('submit', async (event) => { // Don't interrupt event if not form submitting if (!(event instanceof SubmitEvent)) return true if (event.target === null) return true // Disable form sending event.preventDefault() const form = new FormData(event.target) const ipAddress = form.get('ip-address') if (ipAddress === null) return const endpoint = `http://${ipAddress}` await testEndpoint(endpoint) setEndpoint(endpoint) }) /** * A command string. * @typedef {('forward' | 'backward' | 'left' | 'right' | 'stop')} Command */ /** * Send command to the robot. * * @param {Command} command Command to send. * @param {number} value Value of the command if needed. * * @returns {Promise} */ async function sendCommand(command, value) { const endpoint = getEndpoint() const url = new URL(`/get?command=${command}&value=${value}`, endpoint) const response = await fetch(url) const text = await response.text() console.log(text) } /** * Get robot endpoint address. * * @returns {string} */ function getEndpoint() { const endpoint = sessionStorage.getItem('robot-endpoint') if (endpoint === null) { alert("Aucune adresse IP n'a été renseignée !") throw new Error('no given ip address') } return endpoint } /** * Set robot endpoint address. * * @param {string} ip Robot ip. * * @returns void */ function setEndpoint(ip) { sessionStorage.setItem('robot-endpoint', ip) } /** * Test connection to endpoint. * * @param {string} endpoint Endpoint to test for. * * @returns {void} * @throws {Error} Endpoint unreachable. */ async function testEndpoint(endpoint) { try { const response = await fetch(endpoint) if (response.ok) return } catch (cause) { alert(`Impossible de joindre l'adresse "${endpoint}"`) throw new Error(`unable to connect to robot at ${endpoint}`, { cause, }) } } /** * Assign a command to an input. * Do negative command if value < 0 else do positive command. * * @param {Command} negativeCommand Command if value < 0. * @param {Command} positiveCommand Command if value >= 0. * @param {event} event Event of the input. * * @returns {Promise} */ function assignCommands(negativeCommand, positiveCommand, event) { if (event.target === null) return /** @type {HTMLInputElement} */ const target = event.target const value = target.valueAsNumber if (value < 0) { return sendCommand(negativeCommand, Math.abs(value)) } return sendCommand(positiveCommand, value) }