Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exercise mouse coordinates #16

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const MOUSE_USER_INTERFACE = 'user-interface';
export const MOUSE_MOVE = 'mousemove';
export const MOUSE_POSITION = 'mouse-position';
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import { formatCoordinates } from './utils.js';
import { formatCoordinates } from './util.js';

export const showMouseCoordinates = () => {};
export const showMouseCoordinates = (event) => {
debugger;
// read & process user input
const xValue = event.pageX;
const yValue = event.pageY;
// execute core logic
const formattedCoordinates = formatCoordinates(xValue, yValue);
// render result for user
document.getElementById(MOUSE_POSITION).innerHTML = formattedCoordinates;
// log action for developers
console.log('\n--- new coordinates ---');
console.log('x:', xValue);
console.log('y:', yValue);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
document

import './listener.js'

/*document
.getElementById('user-interface')
.addEventListener('mousemove', (event) => {
debugger;
Expand All @@ -16,4 +19,4 @@ document
console.log('\n--- new coordinates ---');
console.log('x:', xValue);
console.log('y:', yValue);
});
});*/
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
import { showMouseCoordinates } from './handler.js';
document
.getElementById(MOUSE_USER_INTERFACE)
.addEventListener(MOUSE_MOVE, showMouseCoordinates);









Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/**
*
*/
export const formatCoordinates = () => {};
export const formatCoordinates = (xValue , yValue) => {
// execute core logic
const formattedCoordinates = 'X: ' + xValue + '\nY: ' + yValue;
return formattedCoordinates;
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { formatCoordinates } from './utils.js';
import { formatCoordinates } from './util.js';

describe('formatCoordinates: formats two numbers into a coordinates string', () => {
it('positive numbers', () => {
Expand Down
18 changes: 18 additions & 0 deletions exercises/convertTemperature/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Convert Temperatures</title>

<link href="./styles.css" rel="stylesheet" />
</head>
<body>
<div id="user-interface">
<input id="temperatures" type="text" value="" />

<ul id="convertedTemperatures"></ul>
</div>

<script type="module" src="./src/init.js"></script>
</body>
</html>
15 changes: 15 additions & 0 deletions exercises/convertTemperature/src/data/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Events
export const ON_CHANGE = 'change';

// Selectors
export const TEMPERATURES_INPUT = 'temperatures';
export const CONVERT_TEMPERATURE_CONTAINER = 'convertedTemperatures';

// Regex
export const SPACE_REGEX = /\s+/;
export const NUMBERS_SPACES_REGEX = /^[0-9\s]*$/;
export const PLACEHOLDER_REGEX = /{([0-9]+)}/g;

// Messages
export const MESSAGE_ERROR_NOT_INTEGER =
"The '{0}' contains values different of integer numbers";
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {
CONVERT_TEMPERATURE_CONTAINER,
MESSAGE_ERROR_NOT_INTEGER,
} from '../data/constants.js';
import { fahrenheitToCelcius } from '../logic/convert-temperatures.js';
import { parseToNumberArray } from '../utils/parsers.js';
import { replacePlaceholders } from '../utils/strings.js';
import { containsOnlyNumbersAndSpaces } from '../utils/validators.js';

const prepareOutputContainer = () => {
const convertedTemperaturesContainer = document.getElementById(
CONVERT_TEMPERATURE_CONTAINER,
);
convertedTemperaturesContainer.innerHTML = '';
return convertedTemperaturesContainer;
};

const renderOutputContainer = (outputContainer, celsiusList) => {
celsiusList.forEach((celsius) => {
const liString = `<li class="number-item">${celsius.toFixed(2)}</li>`;
outputContainer.innerHTML = outputContainer.innerHTML + liString;
});
};

const validateTextInput = (text) => {
if (!text) {
throw new Error();
}

if (!containsOnlyNumbersAndSpaces(text)) {
throw new Error(replacePlaceholders(MESSAGE_ERROR_NOT_INTEGER, text));
}
};

const convertTemperatures = (fahrenheitTextList) => {
validateTextInput(fahrenheitTextList);
const fahrenheitList = parseToNumberArray(fahrenheitTextList);
const celsiusList = fahrenheitList.map((fahrenheit) => {
return fahrenheitToCelcius(fahrenheit);
});
return celsiusList;
};

/**
* Add an 'change' event listener to the element whose id is 'temperatures'.
*
* @param {Event} event - the 'change' event.
*/
export const convertTemperaturesHandler = (event) => {
try {
// Input
const convertedTemperaturesContainer = prepareOutputContainer();

// Logic
const fahrenheitTextList = event.target.value;
const celsiusList = convertTemperatures(fahrenheitTextList);

// Output
renderOutputContainer(convertedTemperaturesContainer, celsiusList);
} catch (error) {
if (error.message) {
window.alert(error.message);
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @jest-environment jsdom
*/

import {
CONVERT_TEMPERATURE_CONTAINER,
MESSAGE_ERROR_NOT_INTEGER,
TEMPERATURES_INPUT,
} from '../data/constants';
import { replacePlaceholders } from '../utils/strings';
import { convertTemperaturesHandler } from './convert-temperatures-handler';

describe('convertTemperaturesHandler', () => {
beforeEach(() => {
document.body.innerHTML = `
<div>
<input id="${TEMPERATURES_INPUT}" />
<div id="${CONVERT_TEMPERATURE_CONTAINER}"></div>
</div>
`;
});

it('should convert the input temperatures', () => {
// GIVEN
const event = { target: { value: '0 32 64' } };
// WHEN
convertTemperaturesHandler(event);
// THEN
const innerHTML = document.getElementById(
CONVERT_TEMPERATURE_CONTAINER,
).innerHTML;
expect(innerHTML).toContain('>-17.78<');
expect(innerHTML).toContain('>0.00<');
expect(innerHTML).toContain('>17.78<');
});

it('should show an alert when invalid input', () => {
// GIVEN
const input = '0 invalid 64';
const event = { target: { value: input } };
window.alert = jest.fn();
// WHEN
convertTemperaturesHandler(event);
// THEN
expect(window.alert).toHaveBeenCalledWith(
replacePlaceholders(MESSAGE_ERROR_NOT_INTEGER, input),
);
});
});
4 changes: 4 additions & 0 deletions exercises/convertTemperature/src/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { convertTemperaturesHandler } from './handlers/convert-temperatures-handler.js';
import { addTemperaturesChangeListener } from './listeners/temperatures-input-listener.js';

addTemperaturesChangeListener(convertTemperaturesHandler);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ON_CHANGE, TEMPERATURES_INPUT } from '../data/constants.js';

/**
* Add an 'change' event listener to the element whose id is 'temperatures'.
*
* @param {function} handler - Callback function to be called when the event occurs.
*/
export const addTemperaturesChangeListener = (handler) => {
document
.getElementById(TEMPERATURES_INPUT)
?.addEventListener(ON_CHANGE, handler);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @jest-environment jsdom
*/

import { ON_CHANGE, TEMPERATURES_INPUT } from '../data/constants';
import { addTemperaturesChangeListener } from './temperatures-input-listener';

describe('addTemperatureChangeListener', () => {
beforeEach(() => {
document.body.innerHTML = `
<div>
<input id="${TEMPERATURES_INPUT}" />
</div>
`;
});

it('should add a handler to the temperature change', () => {
// GIVEN
const handler = jest.fn();
const dispatchChangeTemperatures = () => {
document
.getElementById(TEMPERATURES_INPUT)
.dispatchEvent(new window.Event(ON_CHANGE));
};
// WHEN
addTemperaturesChangeListener(handler);
dispatchChangeTemperatures();
// THEN
expect(handler).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Convert a temperature in Fahrenheit degrees to Celcius degrees.
*
* @param {number} fahrenheit - Temperature in Fahrenheit degrees.
* @returns {number} - Temperature in Celcius degrees.
*/
export const fahrenheitToCelcius = (fahrenheit) => {
return ((fahrenheit - 32) * 5) / 9;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { fahrenheitToCelcius } from './convert-temperatures';

describe('fahrenheitToCelcius', () => {
describe.each`
fahrenheit | expected
${0} | ${-17.77777777777778}
${32} | ${0}
${64} | ${17.77777777777778}
`('$fahrenheit fahrenheit', ({ fahrenheit, expected }) => {
it(`returns ${expected} celcius`, () => {
expect(fahrenheitToCelcius(fahrenheit)).toEqual(expected);
});
});
});
18 changes: 18 additions & 0 deletions exercises/convertTemperature/src/utils/parsers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { SPACE_REGEX } from '../data/constants.js';

/**
* Convert a text containing numbers to an array of numbers.
* If the input text contains non valid numbers, NaN is used as its substitute.
*
* @param {string} text - The text to be parsed.
* @returns {number[]} - Array of numbers.
*/
export const parseToNumberArray = (text) => {
if (text) {
return text
.trim()
.split(SPACE_REGEX)
.map((textNumber) => Number(textNumber));
}
return [];
};
18 changes: 18 additions & 0 deletions exercises/convertTemperature/src/utils/parsers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { parseToNumberArray } from './parsers';

describe('parseToNumberArray', () => {
describe.each`
text | expected
${null} | ${[]}
${undefined} | ${[]}
${''} | ${[]}
${'1 2 3'} | ${[1, 2, 3]}
${' \t 1 \n 2 3 '} | ${[1, 2, 3]}
${'-1 -2 -3'} | ${[-1, -2, -3]}
${'1 a @'} | ${[1, NaN, NaN]}
`('text $text', ({ text, expected }) => {
it(`returns ${expected}`, () => {
expect(parseToNumberArray(text)).toEqual(expected);
});
});
});
18 changes: 18 additions & 0 deletions exercises/convertTemperature/src/utils/strings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { PLACEHOLDER_REGEX } from '../data/constants.js';

/**
* Returns a new string with all placeholders ({0}, {1}, {n}) replaced.
* Reference: https://medium.com/@onlinemsr/javascript-string-format-the-best-3-ways-to-do-it-c6a12b4b94ed
*
* @param {string} template - The string with placeholders.
* @param {string[]} args - The replacements.
* @returns {string} - The string with all placeholders ({0}, {1}, {n}) replaced.
*/
export const replacePlaceholders = (template, ...args) => {
if (template) {
return template.replace(PLACEHOLDER_REGEX, function (match, index) {
return typeof args[index] === 'undefined' ? match : args[index];
});
}
return template;
};
24 changes: 24 additions & 0 deletions exercises/convertTemperature/src/utils/strings.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { replacePlaceholders } from './strings';

describe('replacePlaceholders', () => {
describe.each`
text | replacements | expected
${null} | ${[]} | ${null}
${null} | ${['text']} | ${null}
${''} | ${[]} | ${''}
${''} | ${['text']} | ${''}
${'text'} | ${['text']} | ${'text'}
${'{0} text {0}'} | ${['zero']} | ${'zero text zero'}
${'{0} text {1}'} | ${['zero', 'one']} | ${'zero text one'}
${'{0} text {1}'} | ${['zero', 'one']} | ${'zero text one'}
${'{0} text {1}'} | ${[]} | ${'{0} text {1}'}
${'{0} text {1}'} | ${['zero']} | ${'zero text {1}'}
`(
'text $text with replacements $replacements',
({ text, replacements, expected }) => {
it(`returns ${expected}`, () => {
expect(replacePlaceholders(text, ...replacements)).toBe(expected);
});
},
);
});
11 changes: 11 additions & 0 deletions exercises/convertTemperature/src/utils/validators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { NUMBERS_SPACES_REGEX } from '../data/constants.js';

/**
* Check if the input text contains only number characters or spaces.
*
* @param {string} text - The text to be checked.
* @returns {boolean} - It returns true if the text match with /^[0-9\s]*$/ or false otherwise.
*/
export const containsOnlyNumbersAndSpaces = (text) => {
return NUMBERS_SPACES_REGEX.test(text);
};
Loading