Beispiel:JS-komplexere-dialog-box.html
Aus SELFHTML-Wiki
<!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>