Beispiel:Lotto-4.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!doctype html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<link rel="stylesheet" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css">
	<title>Lotto - 6 aus 49</title>
	<style>
.lotto input {
	position: absolute !important;
	clip: rect(1px, 1px, 1px, 1px);
	padding:0 !important;
	border:0 !important;
	height: 1px !important;
	width: 1px !important;
	overflow: hidden;
}

.lotto label {
	position: relative;
	text-align: center;
	color: firebrick;
	border: thin solid firebrick;
	line-height: 1.5;
}

.lotto :checked + label::after {
  content: "×";
	position: absolute;
	left: -0.35rem;
	top: -1.25rem;
	right: 0;
	font-size: 2.5rem;
	color: darkblue;
	opacity: .6;
}

.lotto fieldset {
	display: grid;
	gap: .25rem;
    width: min-content;
}

.lotto fieldset:first-of-type {
	grid-template: repeat(7, 1.5rem) / repeat(7, 1.5rem);
}

.lotto fieldset:last-of-type {
	grid-template: 1.5rem / repeat(10, 1.5rem);
}

.lotto .error,
.lotto .success {
	padding: 1rem 2rem;
}

.lotto .error {
    background: #ffdddd;
    color: red;
}

.lotto .success {
    background: #ddffdd;
    color: green;
}
	</style>
	<script>
class Lotto {

	/**
	* display alerts to the user
	*/
	alert (text, type) {
		if (text) {

			setTimeout(
				() => {
					this.alerts.textContent = text;
					this.alerts.className = (type ? type : "error");
				},
				50
			);

		} else {

			// reset
			this.alerts.textContent = "";
			this.alerts.className = "";
		}
	}

	/**
	* GUI element (<p>)
	*/
	alerts = document.createElement("p");

	/**
	* setup
	*/
	constructor () {

		this.createGUI();

		document.addEventListener("change", e => { this.handleChange(e); });
		document.addEventListener("click", e => { this.handleClick(e); });

		// polyfill for native Array.shuffle method
		if (!Array.prototype.shuffle) {
			// source: https://medium.com/@nitinpatel_20236/-15ea3f84bfb
			Array.prototype.shuffle = function () {
				const a = this;
				var i = a.length - 1;
				while (i > 0) {
					const j = Math.floor(Math.random() * i);
					const temp = a[i];
					a[i] = a[j];
					a[j] = temp;
					i--;
				}
				return a;
			};
		}
	}

	/**
	* GUI container (<form>)
	*/
	container = document.createElement("form");

	/**
	* create complete GUI
	*/
	createGUI () {
		// container
		this.container.classList.add("lotto");
		document.body.appendChild(this.container);

		// selection n out of m
		const nm = this.container.appendChild(
			document.createElement("fieldset")
		);

		nm.appendChild(document.createElement("legend"));
		nm.lastChild.textContent = "6 aus 49";

		for (var i = 1; i <= this.selection.m; i++) {

			// <input type="checkbox" id="i23">
			nm.appendChild(document.createElement("input"));
			nm.lastChild.id = "i"+i;
			nm.lastChild.type = "checkbox";

			// <label for="i23">23</label>
			nm.appendChild(document.createElement("label"));
			nm.lastChild.htmlFor = "i"+i;
			nm.lastChild.textContent = i;
		}

		// additional selection 1 out of 10
		// selection n out of m
		const s = this.container.appendChild(
			document.createElement("fieldset")
		);

		s.appendChild(document.createElement("legend"));
		s.lastChild.textContent = "Superzahl";

		for (var i = 1; i < 11; i++) {

			// <input type="checkbox" id="s10">
			s.appendChild(document.createElement("input"));
			s.lastChild.id = "s"+i;
			s.lastChild.name = "s";
			s.lastChild.type = "radio";

			if (1 == i) {
				s.lastChild.setAttribute("checked", "checked");
			}

			// <label for="s10">10</label>
			s.appendChild(document.createElement("label"));
			s.lastChild.htmlFor = "s"+i;
			s.lastChild.textContent = i;
		}

		// button
		const b = this.container.appendChild(
			document.createElement("p")
		);

		b.appendChild(document.createElement("button"));
		b.lastChild.textContent = "Ziehung starten!";
		b.lastChild.type = "button";

		// alerts
		this.container.appendChild(this.alerts);
	}

	/**
	* react to change events
	*
	* @param Object
	*/
	handleChange (e) {
		const nm = this.container.querySelectorAll('[id^="i"]:checked');

		// reset alerts
		this.alert();

		// are we inside limits?
		if (nm.length > this.selection.n) {

			// revert last change
			e.target.click();
			this.alert(
				[
					"Sie können maximal",
					this.selection.n,
					"Zahlen für die Ziehung auswählen!"
				].join(" ")
			);
		}
	}

	/**
	* react to click events
	*
	* @param Object
	*/
	handleClick (e) {
		if (this.container.querySelector("button") == e.target) {
			// check required number of selections
			const
				nm = this.container.querySelectorAll('[id^="i"]:checked'),
				s = this.container.querySelectorAll('[id^="s"]:checked');

			var errors = [];

			// reset alerts
			this.alert();

			if (nm.length < this.selection.n) {
				errors.push(
					[
						"Sie benötigen",
						this.selection.n,
						"Zahlen für die Ziehung!"
					].join(" ")
				);
			}

			if (!s.length) {
				errors.push(
					"Sie haben noch keine Superzahl ausgewählt!"
				);
			}

			if (errors.length) {

				this.alert(errors.join(" - "));

			} else {

				this.alert(
					[
						"Lottozahlen:",
						this.pick_n_outOf_m(
							this.selection.n,
							this.selection.m
						),
						" - Superzahl:",
						this.pick_n_outOf_m(1, 10)
					].join(" "),
					"success"
				);
			}
		}
	}

	/**
	* selection size
	*
	* @param Object
	*/
	selection = { n: 6, m: 49 };

	/**
	* pick n from a pool of numbers ranged from 1 to m
	*
	* @param int
	* @param int
	*/
	pick_n_outOf_m (size, highestNumber) {
		const pool = Array(highestNumber)
			.fill() // damit map() so gelingt
			.map((_, i) => i + size) // Werte von n-m eintragen
			.shuffle();

		const pick = pool.slice(0, size);
		pick.sort();

		return pick;
	}

}

document.addEventListener('DOMContentLoaded', () => {
	new Lotto();
});
	</script>
</head>
<body>
	<h1>Lotto – 6 aus 49</h1>
	<p class="warnung">Glücksspiel kann süchtig machen.</p>
</body>
</html>