template_artikel Archive - Seite 10 von 39 - andererseits.org
Zum Inhalt springen
Viele Menschen finden: Die Polizei macht unsere Gesellschaft sicher. Der Journalist Mohamed Amjahid sagt: Für manche Menschen ist die Polizei gefährlich. Wir haben ihn gefragt, warum das so ist.
Polizei-Einsätze können für Menschen in psychischen Ausnahme-Situationen tödlich enden. Welche Ideen für eine bessere Polizei-Arbeit gibt es?
Wir haben gemeinsam mit dem ZDF Magazin Royale mit Jan Böhmermann recherchiert. Die Ergebnisse in einfacher Sprache.
Menschen mit psychischen Krankheiten über ihre Erfahrungen mit der Polizei
Bahar Sayed ist Autistin. Sie streitet seit Jahren um Barriere-Freiheit an der Film-Akademie in Wien. Der Konflikt eskaliert, als die Universität ihre Entscheidungs-Fähigkeit von einem Gericht prüfen lässt.
Menschen mit psychischen Krankheiten über ihre Erfahrungen mit der Polizei
Wir wollten von Theatern, Kultur-Ministerien, Schau-Spiel-Schulen und Ticket-Verkaufs-Stellen wissen: Wie barrierefrei ist Kultur in Deutschland? Mehr als 270 Stellen haben wir angefragt. Weniger als ein Viertel wollte uns auf alle Fragen antworten. Was wir trotzdem wissen und welche Widersprüche sichtbar wurden.
Unsere Autorin Leonie Schüler ist vom Nacht-Leben meistens ausgeschlossen. Diesen Sommer hat sie es selbst in die Hand genommen.
Die Schauspielerinnen Lucy Wilke und Johanna Kappauf arbeiten an den Münchner Kammerspielen. Ihr Weg in die Kunst war nicht selbstverständlich. Denn deutsche Theater sind immer noch alles andere als inklusiv.
Über den Alltag einer Familie mit Behinderungen
Um dir ein optimales Erlebnis zu bieten, verwenden wir Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wenn du diesen Technologien zustimmst, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn du deine Zustimmung nicht erteilst oder zurückziehst, können bestimmte Merkmale und Funktionen beeinträchtigt werden.
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt.
Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Zustimmung verwalten
. No dependencies.
* Keeps WordPress/MediaElement playback; uses native inputs for accessibility.
* Optional on : data-audio-title="Titel des Artikels".
*/
(() => {
"use strict";
if (window.andererseitsAudio) {
window.andererseitsAudio.scan();
return;
}
let nextId = 0;
const enhanced = new WeakSet();
const players = new Set();
const clock = (value) => {
const seconds = Math.max(0, Math.floor(value || 0));
const parts = [Math.floor(seconds / 60) % 60, seconds % 60];
if (seconds >= 3600) parts.unshift(Math.floor(seconds / 3600));
return parts.map((part) => String(part).padStart(2, "0")).join(":");
};
const spokenTime = (value) => {
const seconds = Math.max(0, Math.floor(value || 0));
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
return [
hours && `${hours} ${hours === 1 ? "Stunde" : "Stunden"}`,
minutes && `${minutes} ${minutes === 1 ? "Minute" : "Minuten"}`,
`${seconds % 60} ${seconds % 60 === 1 ? "Sekunde" : "Sekunden"}`,
]
.filter(Boolean)
.join(", ");
};
function enhance(audio) {
const root = audio.closest(".mejs-container.mejs-audio.wp-audio-shortcode");
const player = audio.player;
if (!root || !player || !player.media || enhanced.has(root)) return;
const controls = root.querySelector(".mejs-controls");
const rail = root.querySelector(".mejs-time-rail");
const play = root.querySelector(".mejs-playpause-button > button");
let muteBox = root.querySelector(".mejs-volume-button");
if (!controls || !rail || !play) return;
enhanced.add(root);
const id = `ae-audio-${++nextId}`;
if (!audio.id) audio.id = `${id}-media`;
const precedingWidget =
root.closest(".elementor-widget")?.previousElementSibling;
const nearbyTitle =
precedingWidget?.matches(
".elementor-widget-text-editor, .elementor-widget-heading",
) && precedingWidget.textContent.trim().length <= 120
? precedingWidget.textContent.trim()
: "";
const explicitTitle =
audio.dataset.audioTitle ||
root.closest("[data-audio-title]")?.dataset.audioTitle ||
audio.getAttribute("aria-label");
const pageTitle = (
root.closest("article")?.querySelector("h1") ||
document.querySelector("h1")
)?.textContent.trim();
const title =
explicitTitle ||
nearbyTitle ||
(pageTitle ? `${pageTitle}, Audio ${nextId}` : "");
root.setAttribute("role", "group");
root.setAttribute(
"aria-label",
title ? `Audio: ${title}` : `Audioplayer ${nextId}`,
);
root.removeAttribute("tabindex");
const oldTitle = root.previousElementSibling;
if (oldTitle?.classList.contains("mejs-offscreen")) oldTitle.hidden = true;
// MediaElement's global shortcuts interfere with buttons/selects and
// restart paused audio when seeking. Native controls own their keys.
player.options.enableKeyboard = false;
player.options.autoRewind = false;
player.options.playText = "Wiedergeben";
player.options.pauseText = "Pausieren";
// −10 / +10 flank Play, so visual and tab order match.
const skipBack = document.createElement("div");
skipBack.className = "ae-audio-skips";
skipBack.innerHTML = `10 `;
const skipForward = document.createElement("div");
skipForward.className = "ae-audio-skips";
skipForward.innerHTML = `10 `;
const tools = document.createElement("div");
tools.className = "ae-audio-tools";
tools.innerHTML = `
1×
Lautstärke
`;
const status = document.createElement("div");
status.className = "ae-audio-status ae-audio-sr";
status.setAttribute("role", "status");
status.setAttribute("aria-live", "polite");
status.setAttribute("aria-atomic", "true");
const error = document.createElement("p");
error.className = "ae-audio-error";
error.hidden = true;
const help = document.createElement("span");
help.id = `${id}-help`;
help.className = "ae-audio-sr";
help.textContent =
"Pfeiltasten: 10 Sekunden. Bild auf oder ab: 30 Sekunden. Pos1: Anfang. Ende: Schluss.";
const seek = document.createElement("input");
seek.type = "range";
seek.className = "ae-audio-range ae-audio-seek";
seek.min = "0";
seek.max = "0";
seek.step = "1";
seek.value = "0";
seek.setAttribute("aria-label", "Wiedergabeposition");
seek.setAttribute("aria-describedby", help.id);
const tooltip = document.createElement("span");
tooltip.className = "ae-audio-tooltip";
tooltip.setAttribute("aria-hidden", "true");
const originalSlider = root.querySelector(".mejs-time-total");
originalSlider?.setAttribute("aria-hidden", "true");
originalSlider?.setAttribute("tabindex", "-1");
rail.append(seek, tooltip, help);
const inner = root.querySelector(".mejs-inner");
play.parentElement.before(skipBack);
play.parentElement.after(skipForward);
controls.append(tools);
inner.append(error, status);
if (!muteBox) {
muteBox = document.createElement("div");
muteBox.className = "mejs-button mejs-volume-button mejs-mute";
muteBox.innerHTML =
' ';
}
const volumeBox = tools.querySelector(".ae-audio-volume");
volumeBox.prepend(muteBox);
const mute = muteBox?.querySelector("button");
const volume = tools.querySelector("input");
const speed = tools.querySelector(".ae-audio-rate");
const skipButtons = [skipBack, skipForward].map((box) => box.firstChild);
let previousVolume = audio.volume || 0.8;
root.querySelectorAll("button, input, select").forEach((control) => {
control.setAttribute("aria-controls", audio.id);
});
// Retain tab order and browser/AT default behavior. No single-letter
// shortcuts, application mode, focus trapping or document key listeners.
let announcementTimer;
function announce(message) {
clearTimeout(announcementTimer);
status.textContent = "";
announcementTimer = setTimeout(() => {
if (root.isConnected) status.textContent = message;
}, 60);
}
const duration = () =>
Number.isFinite(audio.duration) && audio.duration > 0
? audio.duration
: 0;
function loadMetadata() {
if (audio.preload === "none" && !audio.readyState && !audio.error) {
audio.preload = "metadata";
audio.load();
}
}
// Respect lazy loading: only request metadata for the player a person
// enters, rather than downloading every clip on a page with many players.
root.addEventListener("focusin", loadMetadata);
root.addEventListener("pointerenter", loadMetadata, { once: true });
// Handle rejected play promises (network errors, browser restrictions)
// instead of letting MediaElement silently discard them.
play.addEventListener("click", (event) => {
event.stopPropagation();
if (!audio.paused && !audio.ended) {
audio.pause();
return;
}
if (audio.ended) audio.currentTime = 0;
const attempt = audio.play();
attempt?.catch((reason) => {
if (reason.name === "AbortError") return;
error.hidden = false;
error.textContent =
"Wiedergabe nicht möglich. Bitte erneut versuchen oder die Seite neu laden.";
announce(error.textContent);
syncButtons();
});
});
function paintRange(input, value, maximum) {
input.style.setProperty(
"--ae-fill",
`${maximum ? (value / maximum) * 100 : 0}%`,
);
}
function updateTime() {
const maximum = duration();
const current = Math.min(maximum, Math.max(0, audio.currentTime || 0));
seek.max = String(maximum);
seek.value = String(current);
seek.disabled = !maximum || !!audio.error;
seek.setAttribute(
"aria-valuetext",
maximum
? `${spokenTime(current)} von ${spokenTime(maximum)}`
: "Dauer noch nicht verfügbar",
);
paintRange(seek, current, maximum);
tooltip.textContent = clock(current);
skipButtons.forEach((button) =>
button.setAttribute("aria-disabled", String(!maximum || !!audio.error)),
);
}
function syncButtons() {
const playLabel =
audio.paused || audio.ended ? "Wiedergeben" : "Pausieren";
if (play.getAttribute("aria-label") !== playLabel)
play.setAttribute("aria-label", playLabel);
if (play.title !== playLabel) play.title = playLabel;
if (mute) {
const silent = audio.muted || audio.volume === 0;
const label = silent ? "Ton einschalten" : "Stummschalten";
if (mute.getAttribute("aria-label") !== label)
mute.setAttribute("aria-label", label);
if (mute.title !== label) mute.title = label;
muteBox.classList.toggle("mejs-mute", !silent);
muteBox.classList.toggle("mejs-unmute", silent);
}
}
function syncVolume() {
if (audio.volume > 0) previousVolume = audio.volume;
const value = audio.muted ? 0 : Math.round(audio.volume * 100);
volume.value = String(value);
volume.setAttribute(
"aria-valuetext",
`${value} Prozent${audio.muted ? ", stummgeschaltet" : ""}`,
);
paintRange(volume, value, 100);
syncButtons();
}
function seekTo(value, announcePosition = false) {
if (!duration() || audio.error) {
loadMetadata();
if (announcePosition)
announce(
audio.error
? "Audio ist nicht verfügbar."
: "Audio wird geladen. Bitte kurz warten.",
);
return;
}
try {
audio.currentTime = Math.max(0, Math.min(duration(), value));
updateTime();
if (announcePosition)
announce(
`Position: ${spokenTime(audio.currentTime)} von ${spokenTime(duration())}.`,
);
} catch {
announce("Diese Position ist noch nicht verfügbar.");
}
}
skipButtons.forEach((button) =>
button.addEventListener("click", () => {
seekTo(audio.currentTime + Number(button.dataset.seconds), true);
}),
);
seek.addEventListener("input", () => seekTo(Number(seek.value)));
seek.addEventListener("keydown", (event) => {
if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
return;
const offsets = {
ArrowLeft: -10,
ArrowDown: -10,
ArrowRight: 10,
ArrowUp: 10,
PageDown: -30,
PageUp: 30,
};
const target =
event.key === "Home"
? 0
: event.key === "End"
? duration()
: event.key in offsets
? audio.currentTime + offsets[event.key]
: null;
if (target === null) return;
event.preventDefault();
event.stopPropagation();
seekTo(target);
});
seek.addEventListener("pointermove", (event) => {
const box = seek.getBoundingClientRect();
const fraction = Math.max(
0,
Math.min(1, (event.clientX - box.left) / box.width),
);
tooltip.textContent = clock(fraction * duration());
});
volume.addEventListener("input", () => {
const value = Number(volume.value) / 100;
audio.volume = value;
audio.muted = value === 0;
if (Math.abs(audio.volume - value) > 0.01) {
announce(
"Bitte die Lautstärketasten des Geräts verwenden. Dieser Browser erlaubt keinen Lautstärkeregler.",
);
}
syncVolume();
});
mute.addEventListener(
"click",
(event) => {
event.stopImmediatePropagation();
if (audio.muted || audio.volume === 0) {
if (audio.volume === 0) audio.volume = previousVolume;
audio.muted = false;
} else audio.muted = true;
syncVolume();
},
true,
);
// Native range supplies arrows/Home/End, including AT increment actions.
// Escape hides the slider shown on hover/focus (WCAG 1.4.13) and returns
// focus to the mute button; it reappears once focus or pointer re-enter.
function dismissVolume(event) {
if (event.key !== "Escape" || getComputedStyle(volume).opacity === "0")
return;
event.preventDefault();
event.stopPropagation();
volumeBox.classList.add("ae-audio-volume-dismissed");
if (document.activeElement === volume) mute.focus();
}
const restoreVolume = () =>
volumeBox.classList.remove("ae-audio-volume-dismissed");
volumeBox.addEventListener("keydown", dismissVolume);
// While hovered, focus may be elsewhere on the page.
volumeBox.addEventListener("pointerenter", () =>
document.addEventListener("keydown", dismissVolume),
);
volumeBox.addEventListener("pointerleave", () => {
document.removeEventListener("keydown", dismissVolume);
restoreVolume();
});
volume.addEventListener("focus", restoreVolume);
volumeBox.addEventListener("focusout", (event) => {
if (!volumeBox.contains(event.relatedTarget)) restoreVolume();
});
// One button cycles the tempo; the visible value is part of its name.
const rates = [1, 1.25, 1.5, 2, 0.5, 0.75];
const rateText = (rate) => `${String(rate).replace(".", ",")}×`;
function syncRate() {
speed.textContent = rateText(audio.playbackRate);
speed.setAttribute(
"aria-label",
`Abspielgeschwindigkeit ${rateText(audio.playbackRate)}`,
);
}
speed.addEventListener("click", () => {
const next =
rates[(rates.indexOf(audio.playbackRate) + 1) % rates.length];
try {
audio.playbackRate = next;
announce(
`Abspielgeschwindigkeit: ${String(audio.playbackRate).replace(".", ",")} mal.`,
);
} catch {
announce(
"Diese Abspielgeschwindigkeit wird vom Browser nicht unterstützt.",
);
}
syncRate();
});
audio.addEventListener("ratechange", syncRate);
[
"timeupdate",
"durationchange",
"loadedmetadata",
"emptied",
"seeked",
].forEach((name) => audio.addEventListener(name, updateTime));
["play", "playing", "pause", "ended", "loadedmetadata"].forEach((name) =>
audio.addEventListener(name, syncButtons),
);
// MediaElement can overwrite localized labels in a later renderer event.
// Observe only those two attributes, and write only when different.
const labelObserver = new MutationObserver(syncButtons);
[play, mute].forEach((button) =>
labelObserver.observe(button, {
attributes: true,
attributeFilter: ["aria-label", "title"],
}),
);
audio.addEventListener("volumechange", syncVolume);
audio.addEventListener("play", () => {
error.hidden = true;
for (const other of players) {
if (!other.isConnected) players.delete(other);
else if (other !== audio && !other.paused) other.pause();
}
});
audio.addEventListener("ended", () => announce("Wiedergabe beendet."));
const showError = () => {
error.hidden = false;
error.textContent =
"Audio konnte nicht geladen werden. Bitte die Seite neu laden oder es später erneut versuchen.";
announce(error.textContent);
updateTime();
};
audio.addEventListener("error", showError);
audio.addEventListener("loadstart", () => {
error.hidden = true;
});
players.add(audio);
root.classList.add("ae-audio-enhanced");
updateTime();
syncVolume();
syncRate();
if (audio.error) showError();
}
function scan() {
document.querySelectorAll("audio.wp-audio-shortcode").forEach(enhance);
}
window.andererseitsAudio = { scan };
// WordPress and Elementor may initialize/add players after this snippet.
let queued = false;
const observer = new MutationObserver((records) => {
if (
queued ||
!records.some((record) =>
[...record.addedNodes].some(
(node) =>
node.nodeType === 1 &&
(node.matches("audio, .mejs-controls") ||
node.querySelector("audio, .mejs-controls")),
),
)
)
return;
queued = true;
requestAnimationFrame(() => {
queued = false;
scan();
});
});
function start() {
scan();
observer.observe(document.body, { childList: true, subtree: true });
}
if (document.readyState === "loading")
document.addEventListener("DOMContentLoaded", start, { once: true });
else start();
})();
/* andererseits Audio-Player Erweiterung – ENDE */