refactor(client): ♻️ split script into modules
This commit is contained in:
parent
95c471e5d8
commit
a1d53fcd59
163
client/app.js
163
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<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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)
|
||||
|
|
82
client/src/handlers.js
Normal file
82
client/src/handlers.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
import { sendCommand, setEndpoint, testEndpoint } from './utils.js'
|
||||
|
||||
/**
|
||||
* Handler for settings form.
|
||||
*
|
||||
* @param {Event} event Settings form submit event.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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)
|
||||
}
|
||||
}
|
88
client/src/utils.js
Normal file
88
client/src/utils.js
Normal file
|
@ -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<void>}
|
||||
*/
|
||||
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<void>}
|
||||
*/
|
||||
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)
|
||||
}
|
Loading…
Reference in a new issue