128 lines
2.8 KiB
JavaScript
128 lines
2.8 KiB
JavaScript
const NOTIFICATION_TIMEOUT = 3000;
|
|
|
|
class Dice {
|
|
#array = []
|
|
|
|
/**
|
|
* Instantiate a dice with a given number of sides
|
|
* @param {Number} numSides The number of sides
|
|
*/
|
|
constructor ( numSides = 6 ) {
|
|
for (let n = 0; n < numSides; n++) {
|
|
this.#array.push(n+1);
|
|
}
|
|
this.numSides = numSides;
|
|
}
|
|
|
|
/**
|
|
* Randomly shuffle an array
|
|
* https://stackoverflow.com/a/2450976/1293256
|
|
* @param {Array} array The array to shuffle
|
|
* @return {Array} The shuffled array
|
|
*/
|
|
static #shuffle (array) {
|
|
let currentIndex = array.length;
|
|
let temporaryValue, randomIndex;
|
|
|
|
// While there remain elements to shuffle...
|
|
while (0 !== currentIndex) {
|
|
// Pick a remaining element...
|
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
currentIndex -= 1;
|
|
|
|
// And swap it with the current element.
|
|
temporaryValue = array[currentIndex];
|
|
array[currentIndex] = array[randomIndex];
|
|
array[randomIndex] = temporaryValue;
|
|
}
|
|
|
|
return array;
|
|
}
|
|
/**
|
|
* Roll the dice
|
|
* @return {Number} The result of the rolling
|
|
*/
|
|
roll () {
|
|
return Dice.#shuffle(this.#array)[0];
|
|
}
|
|
}
|
|
|
|
class DiceButton extends HTMLElement {
|
|
|
|
#dice;
|
|
|
|
/**
|
|
* Instantiate the component
|
|
*/
|
|
constructor() {
|
|
|
|
// Inherit parent class properties
|
|
super();
|
|
|
|
// Define component properties and instantiate a dice
|
|
this.#dice = new Dice(this.getAttribute("dice-sides") || 6);
|
|
|
|
// Render the initial HTML content of the component
|
|
let userHTML = this.innerHTML.trim();
|
|
|
|
this.innerHTML = `
|
|
<p>
|
|
<button>${userHTML ? userHTML : `Roll a ${this.#dice.numSides} sided dice`}</button>
|
|
</p>
|
|
<div dice-result></div>
|
|
`;
|
|
|
|
// Get result element
|
|
this.result = this.querySelector('[dice-result]')
|
|
|
|
// LIsten for events
|
|
this.addEventListener('click', this);
|
|
}
|
|
|
|
/**
|
|
* Show a status message in the form
|
|
* @param {String} msg The message to display
|
|
*/
|
|
showStatus (msg) {
|
|
// Create a notification
|
|
let notification = document.createElement('div');
|
|
notification.setAttribute('role', 'status');
|
|
|
|
// Inject it into the DOM
|
|
this.result.append(notification);
|
|
|
|
// Add text after it's in the UI
|
|
setTimeout(function () {
|
|
notification.textContent = msg;
|
|
}, 1);
|
|
|
|
// Remove it after 4 seconds
|
|
setTimeout(function () {
|
|
notification.remove();
|
|
}, NOTIFICATION_TIMEOUT);
|
|
|
|
}
|
|
|
|
/**
|
|
* Handle events
|
|
* @param {Event} event The event object
|
|
*/
|
|
handleEvent (event) {
|
|
this[`on${event.type}`](event);
|
|
}
|
|
|
|
/**
|
|
* Handle the click event
|
|
* @param {Event} event The event object
|
|
*/
|
|
onclick (event) {
|
|
this.showStatus(`You rolled a ${this.#dice.roll()}`);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// Define the new web component
|
|
if ('customElements' in window) {
|
|
customElements.define('dice-button', DiceButton);
|
|
}
|