From a1d53fcd59a84611e178e66d780b3c0b37cb35a9 Mon Sep 17 00:00:00 2001 From: Julien Oculi Date: Tue, 25 Jun 2024 15:16:19 +0200 Subject: [PATCH] refactor(client): :recycle: split script into modules --- client/app.js | 163 ++--------------------------------------- client/src/handlers.js | 82 +++++++++++++++++++++ client/src/utils.js | 88 ++++++++++++++++++++++ 3 files changed, 176 insertions(+), 157 deletions(-) create mode 100644 client/src/handlers.js create mode 100644 client/src/utils.js diff --git a/client/app.js b/client/app.js index 7d8f595..dac7379 100644 --- a/client/app.js +++ b/client/app.js @@ -1,3 +1,6 @@ +import { controlButtonHandler, keyboardHandler, settingsHandler } from './src/handlers.js' +import { assignCommands } from './src/utils.js' + // Input handlers document .querySelector('#move-input') @@ -14,165 +17,11 @@ document 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)) - }) + button.addEventListener('click', controlButtonHandler) } // 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) - } -}) +document.addEventListener('keydown', keyboardHandler) // 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) -} +document.querySelector('#settings').addEventListener('submit', settingsHandler) diff --git a/client/src/handlers.js b/client/src/handlers.js new file mode 100644 index 0000000..e90eb43 --- /dev/null +++ b/client/src/handlers.js @@ -0,0 +1,82 @@ +import { sendCommand, setEndpoint, testEndpoint } from './utils.js' + +/** + * Handler for settings form. + * + * @param {Event} event Settings form submit event. + * @returns {Promise} + */ +export async function settingsHandler(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) +} + +/** + * Attach command to touch controls buttons. + * + * @this HTMLButtonElement + * @returns {Promise} + */ +export function controlButtonHandler() { + const { command, value } = this.dataset + + // Check datas are set for button + if (command === undefined || value === undefined) { + alert(`Pas de command ou de valeur assigné au bouton "${this.title}"`) + throw new Error(`no command or value assigned to ${this.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)) +} + +/** + * Handler for keyboard events. + * + * @param {KeyboardEvent} event Keyboard event. + * @returns {Promise} + */ +export function keyboardHandler({ 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) + } +} diff --git a/client/src/utils.js b/client/src/utils.js new file mode 100644 index 0000000..4205481 --- /dev/null +++ b/client/src/utils.js @@ -0,0 +1,88 @@ +/** + * 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} + */ +export 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} + */ +export 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} + */ +export 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. + */ +export 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} + */ +export 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) +}