Beispiel:JS-komplexere-dialog-box.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!doctype html>
<html lang="de">
	<head>
		<meta charset="utf-8">
		<title>Komplexere Dialog-Box</title>
		<link rel="stylesheet" type="text/css" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css" />
		<style>
/* Darstellungen für die Dialog-Box */

dialog {
	background: white;
	border: 1px solid grey;
	border-radius: 0 .5em .5em;
	box-shadow: 0 0 15px 5px #888;
	display: none;
	height: auto;
	padding: .5em 1em;
	position: relative;
	width: 100%;
	z-index:1002;
}

dialog[open] {
	display: block;
}

@media (min-width: 30em) {
  dialog {
	position: absolute;
	top: 50%;
	margin-top: -10em;
	left: 50%;
	margin-left: -10em;
	width: 20em;
  }
}

/* Ebene zwischen Hintergrund und Dialog-Box, Pseudoelement noch nicht implementiert */
dialog::backdrop, #backdrop {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(255, 255, 255, 0.8);
}

dialog .button-row {
	text-align: center;
}

dialog .close {
	position: absolute;
	right: 3px;
	top: 1px;
	height: 2em;
	cursor: pointer;
	background-color: red;
	color: white;
	font-weight: bold;
	font-size: 1.5em;
	border-radius: 0 .5em .5em;
}

dialog [name="ok"] {
	background: #0b0;
	border-radius: 0 .5em .5em;
	color: white;
	font-weight: bold;
	font-size: 1.5em;
}

dialog [name="cancel"] {
	background: #f00;
	border-radius: 0 .5em .5em;
	color: white;
	font-weight: bold;
	font-size: 1.5em;
}

dialog > ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

dialog textarea {
	height: 4em;
	width: 100%;
}

/* Darstellungen für die Demo-Seite */
#result {
	border: 2px solid #888;
	border-radius: 0.5em;
	display: inline-block;
	padding: 0.2em 1em;
}
		</style>
		<script>
'use strict';
document.addEventListener("DOMContentLoaded", function () {
	var button = document.querySelector("main button");

	// Polyfill für Browser, die das dialog-Element nicht komplett unterstützen
	(function () {
		var backdrop;

		Array.prototype.slice.call(
			document.querySelectorAll("dialog")
		).forEach(function (dialog) {
			var callBacks = {
					cancel: function () {},
					ok: function () {}
				},
				close = dialog.querySelector(".close");

			if (!dialog.close) {
				dialog.close = function () {

					if (dialog.hasAttribute("open")) {
						dialog.removeAttribute("open");
					}

					if (backdrop && backdrop.parentNode) {
						backdrop.parentNode.removeChild(backdrop);
					}
				}
			}

			if (!dialog.show) {
				dialog.show = function () {
					var closeButton = dialog.querySelector(".close");

					dialog.setAttribute("open", "open");

					// after displaying the dialog, focus the closeButton inside it
					if (closeButton) {
						closeButton.focus();
					}

					if (!backdrop) {
						backdrop = document.createElement("div");
						backdrop.id = "backdrop";
					}

					document.body.appendChild(backdrop);
				}
			}

			dialog.setCallback = function (key, f) {
				callBacks[key] = f;
			};

			dialog.triggerCallback = function (key) {
				if (typeof callBacks[key] == "function") {
					callBacks[key]();
				}
			};

			if (close) {
				close.addEventListener("click", function () {
					dialog.close();
					dialog.triggerCallback("cancel");
				});
			}

			// handle buttons for user input
			["cancel", "ok"].forEach(function (n) {
				var button = dialog.querySelector('[name="'+n+'"]');

				if (button) {
					button.addEventListener("click", function () {
						dialog.close();
						dialog.triggerCallback(n);
					});
				}
			});
		});

		// ESC and ENTER closes open dialog and triggers corresponding callback
		document.addEventListener(
			"keydown",
			function (event) {
				var currentElement = event.target || event.soureElement,
					prevent = (
						currentElement.tagName
						&& currentElement.tagName.match(/^button|input|select|textarea$/i)
					);

				Array.prototype.slice.call(
					document.querySelectorAll("dialog")
				).forEach(function(dialog) {

					if (dialog.hasAttribute("open")) {

						// ENTER
						if (event.keyCode == 13 && !prevent) {
							dialog.close();

							setTimeout(function () {
								dialog.triggerCallback("ok");
							}, 50);
						}

						// ESC
						if (event.keyCode == 27) {
							dialog.close();

							setTimeout(function () {
								dialog.triggerCallback("cancel");
							}, 50);
						}
					}
				});
			},
			true
		);
	}());

	// komplexere Dialog-Box anzeigen
	window.myDialog = function (data, OK, cancel) {
		var dialog = document.querySelector("#my-dialog"),
			buttonRow = document.querySelector("#my-dialog .button-row"),
			heading = document.querySelector("#my-dialog-heading"),
			element, p, prop;

		if (dialog && buttonRow) {

			// Standard-Titel
			if (heading) {
				heading.textContent = "Eingabe";
			}

			// jedes <ul> und <p> entfernen, außer <p class="button-row">
			Array.prototype.slice.call(
				dialog.querySelectorAll("ul, p:not(.button-row)")
			).forEach(function (p) {
				p.parentNode.removeChild(p);
			});

			// Elemente erstellen und gegebenenfalls mit Inhalten befüllen
			for (prop in data) {

				// alles bekommt ein <p> drumherum
				p = document.createElement("p");

				buttonRow.parentNode.insertBefore(p, buttonRow);

				// simple Textausgabe
				if (data[prop].type && data[prop].type == "info") {
					p.textContent = data[prop].text;
				}

				// anderer Titel
				if (data[prop].type && data[prop].type == "title"
					&& heading
				) {

					heading.textContent = data[prop].text;

					// neues <p> wird hierfür nicht benötigt
					p.parentNode.removeChild(p);
				}

				// numerischer Wert
				if (data[prop].type && data[prop].type == "number") {

					// <label> als Kindelement für Beschriftung
					p.appendChild(document.createElement("label"));
					p.lastChild.appendChild(
						document.createTextNode(data[prop].text + " ")
					);

					// <input type="number">
					element = p.appendChild(
						document.createElement("input")
					);

					if (data[prop].hasOwnProperty("max")) {
						element.max = data[prop]["max"];
					}

					if (data[prop].hasOwnProperty("min")) {
						element.min = data[prop]["min"];
					}

					if (data[prop].hasOwnProperty("step")) {
						element.step = data[prop]["step"];
					}

					element.name = prop;
					element.type = "number";
					element.value = element.min = data[prop]["min"] || 0;

					if (data[prop].default) {
						element.value = data[prop].default;
					}
				}

				// Mehrfachauswahl
				if (data[prop].type && data[prop].type == "multiple") {

					p.textContent = data[prop].text;

					// alle Optionen wandern in ein <ul>
					element = document.createElement("ul");
					buttonRow.parentNode.insertBefore(element, buttonRow);

					data[prop].options.forEach(function (d, index) {
						var input = document.createElement("input"),
							label = document.createElement("label"),
							li = document.createElement("li");

						// <li> in <ul> einhängen
						element.appendChild(li);

						input.id = prop + "-" + index;
						input.name = prop + "-" + index;
						input.type = "checkbox";
						input.value = d;
						li.appendChild(input);

						label.htmlFor = prop + "-" + index;
						label.textContent = " " + d
						li.appendChild(label);

						if (data[prop].default && data[prop].default == d) {
							input.setAttribute("checked", "checked");
						}
					});
				}

				// Einfachauswahl
				if (data[prop].type && data[prop].type == "select") {

					// <label> als Kindelement für Beschriftung
					p.appendChild(document.createElement("label"));
					p.lastChild.appendChild(
						document.createTextNode(data[prop].text + " ")
					);

					// alle Optionen wandern in ein <ul>
					element = p.appendChild(
						document.createElement("select")
					);

					element.name = prop;

					data[prop].options.forEach(function (d) {
						var o = document.createElement("option");

						o.textContent = d;
						o.value = d;

						element.appendChild(o);

						if (data[prop].default && data[prop].default == d) {
							o.setAttribute("selected", "selected");
						}
					});
				}

				// Texteingabe
				if (data[prop].type && data[prop].type == "text") {

					// <label> als Kindelement für Beschriftung
					p.appendChild(document.createElement("label"));
					p.lastChild.appendChild(
						document.createTextNode(data[prop].text)
					);

					// alle Optionen wandern in ein <ul>
					element = p.appendChild(
						document.createElement("textarea")
					);

					element.name = prop;

					if (data[prop].default) {
						element.textContent = data[prop].default;
					}
				}
			}

			dialog.setCallback("cancel", cancel);

			dialog.setCallback("ok", function () {
				var result = {},
					elements;

				// Ergebnisse ermitteln
				for (prop in data) {

					elements = Array.prototype.slice.call(
						dialog.querySelectorAll('[name^="' + prop + '"]')
					);

					if (data[prop].type && data[prop].type == "multiple") {

						result[prop] = [];

						elements.forEach(function (element) {

							if (element.checked) {
								result[prop].push(element.value);
							}
						});

					} else {

						if (data[prop].type != "title"
							&& data[prop].type != "info"
						) {

							result[prop] = null;

							if (elements[0]) {
								result[prop] = elements[0].value;
							}
						}
					}
				}

				// Ergebnisse an die Callback-Funktion zurück geben
				OK(result);
			});

			dialog.show();
		}
	}

	// anzeigen-Button aktivieren
	if (button) {

		button.addEventListener("click", function () {
			myDialog(
				// data
				{
					instructions: {
						text: "Bitte seien Sie jetzt komplett ehrlich und füllen Sie wahrheitsgemäß alles aus!",
						type: "info"
					},
					title: {
						text: "Sonderabfrage",
						type: "title"
					},
					sex: {
						"default": "weiblich",
						options: ["männlich", "weiblich", "divers"],
						text: "Geschlecht",
						type: "select"
					},
					age: {
						"default": 18,
						"max": 150,
						"min": 0,
						step: 1,
						text: "Alter",
						type: "number"
					},
					preferences: {
						"default": "Pop",
						options: ["Jazz", "Swing", "Latin", "Klassik", "Hiphop", "Pop"],
						text: "Diese Musik mag ich gerne",
						type: "multiple"
					},
					message: {
						text: "Das will ich mitteilen",
						type: "text"
					}
				},
				// OK
				function (data) {
					var output = document.querySelector("main pre"),
						prop,
						result = "Ergebnis:\r\n=========\r\n\r\n";

					for (prop in data) {

						result += prop + ":";

						if (typeof data[prop] == "object") {

							data[prop].forEach(function (value, index) {
								result += (index ? "," : "") + "\r\n\t" + value;
							});

						} else {

							result += " " + data[prop];
						}

						result += "\r\n";
					}

					if (output) {
						output.textContent = result;
					}
				},
				// cancel
				function () {
					var output = document.querySelector("main pre");

					if (output) {
						output.textContent = "(kein Ergebnis)";
					}
				}
			);
		});
	}
});
		</script>
	</head>
	<body>
		<h1>Komplexere Dialog-Box</h1>
		<main>
			<p>Eine Dialog-Box mit mehreren Eingabefeldern als modales Fenster.
                          <button>anzeigen</button>.
                        </p>
			<pre id="result"></pre>
		</main>
		<dialog id="my-dialog" role="dialog" aria-labelledby="my-dialog-heading">
			<button class="close">Schließen</button>
			<h2 id="my-dialog-heading">Eingabe</h2>
			<p class="button-row">
				<button name="ok">OK</button>
				<button name="cancel">Abbrechen</button>
			</p>
		</dialog>
	</body>
</html>