Very much a work inprogress — tinkering with your code :).
Wrapping the inputs in a form element and using submit will allow you to take advantage of HTML’s form validation and will prevent you clicking on Calculate without valid inputs. Note, it’s not full proof as you can always change the HTML in devtools, but it’s a move in the right direction.
<div id='phrase'>
<form id='calculate-position'>
<label for='rowInput'>Enter a row A - H</label>
<input type='text' id='rowInput' pattern='[a-hA-H]' placeholder='Enter Row' required>
<label for='colInput'>Enter a column 1 - 12</label>
<input type='number' id='colInput' min='1' max='12' pattern='[0-9]' placeholder=' Enter Column' required>
<button id='calculate'>Calculate</button>
</form>
<output class='target'>The cell number is <b id='cellnum'>?</b></output>
<div id='words'>
<button type='button' id='move-text' type='button'>Move Text Content!</button>
<!-- remove whitespace from inside div html and then we can use :empty in css to change background -->
<div data-id='01'><span class='words' data-id='01'>H1 text</span></div>
<div data-id='02'><span class='words' data-id='02'>H2 text</span></div>
...
<div data-id='10'><span class='words' data-id='10'>G4 text</span></div>
</div>
</div>
Some more tinkering with the get cell number section.
Instead of using a long list of switch cases the start can be calculated using charCodeAt
function calcRowFromChar(char, start = 42, step = -6) {
// e.g. 'b' → upperCase 'B' → charCode is 66 → minus 65 → 1
const charPosInAlphabet = char.toUpperCase().charCodeAt(0) - 65;
// e.g. 42 + 1 * -6 = 36
return start + charPosInAlphabet * step;
}
calcRowFromChar('a') // 42
calcRowFromChar('c') // 30
calcRowFromChar('h') // 0
The global startPos
was bugging me a bit. It had me scrolling up and down the page to see where it was being used. I could be wrong but it made sense to me to pass that directly to the fill
function as an argument instead.
The issue though was how to set startPos
with the calculate handler and make it available to the movebutton handler without making it a global. I opted to wrap it inside of a module pattern which returns the two handlers.
So here is a bit of refactoring, I hope you don’t mind.
function calcRowFromChar(char, start = 42, step = -6) {
// e.g. 'a' → upperCase 'A' → charCode is 65 → minus 65 → 0
const charPosInAlphabet = char.toUpperCase().charCodeAt(0) - 65;
return start + charPosInAlphabet * step;
}
// A module pattern to keep startPos out of the
// global context and only where it is needed
function createHandlers() {
// startPos is local to createHandlers and only
// available to the returned handlers
let startPos = 1;
return {
calculateStart(event) {
// prevent actually submitting the form
event.preventDefault();
const start = 42
// we can access the form elements directly from the form, without querySelecting
const { rowInput, colInput } = event.target.elements;
const rowNum = calcRowFromChar(rowInput.value, start);
const colNum = Number(colInput.value);
startPos = (colNum < 7)
? rowNum + colNum
: rowNum + start + colNum;
document.querySelector('#cellnum').textContent = startPos;
},
moveToGrid(event) {
// disable button
event.target.classList.add('disabled');
// pass in startPos to fill function instead
fill(startPos);
}
};
}
const handlers = createHandlers();
const calculateButton = document.querySelector('#calculate-position');
calculateButton.addEventListener('submit', handlers.calculateStart);
const moveTextBtn = document.querySelector('#move-text');
moveTextBtn.addEventListener('click', handlers.moveToGrid, { once: true });
fill
would need to be ammended accordingly
function fill(startPos) {
...
});
A codepen, with these few ammends