template_artikel Archive - Seite 17 von 39 - andererseits.org
Zum Inhalt springen
Hanna Gugler
ist süchtig nach Fleisch. Sie findet trotzdem: Alle sollten
weniger Fleisch essen.
Wenn Arbeitgeber·innen Menschen mit Behinderungen anstellen, wird das oft als »gelungene Inklusion« bezeichnet.
Aber gelingt sie wirklich?
Arbeits-Unfähigkeit sollte es »nie mehr geben«, Lohn statt Taschengeld dafür
eingeführt werden. Arbeits- und Wirtschafts-Minister Martin Kocher (ÖVP) überrascht
im Interview mit klaren Ansagen. Warum setzt sie die Regierung dann nicht um?
Unser Autor hat einen Vorgeschmack darauf bekommen, wie die Arbeit in einer Werkstätte für Menschen mit Behinderungen abläuft. Er fragt sich: Wissen die Menschen eigentlich, wie es sich anfühlt, wenn einem nichts zugetraut wird?
Werkstätten sollen Menschen mit Behinderungen betreuen und beschäftigen. Einige von ihnen bekommen auch Arbeits-Aufträge von Firmen. Doch die Praxis zeigt: Die Arbeits-Bedingungen sind schlecht und grenzen an Ausbeutung.
Unser Autor hat zu Arbeits-Fähigkeit recherchiert. Ein Text über den Frust, nur darauf reduziert zu werden, was man nicht kann.
Wer ist »arbeitsfähig« und wer nicht? In Österreich wird das schon bei Jugendlichen entschieden. Die Kriterien dafür kennt nicht einmal der Arbeits-Minister.
In der Zeit des National-Sozialismus war das Schloss Hartheim in Oberösterreich ein Ort an dem Menschen mit Behinderungen ermordet wurden.
Heute ist es eine Gedenk-Stätte für die Opfer der Verbrechen.
Ein Studienabschluss ist für Student·innen mit Behinderungen mit Hürden verbunden. In Österreich gibt es dadurch ungleiche Chancen auf Bildung.
Vielen Menschen mit Behinderungen gelingt es nicht, einen Job zu finden. Dabei gibt es das „Netzwerk Berufliche Assistenz“. Wie kann das sein?
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 */