<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://schwarzatal.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-Mastodon.js</id>
	<title>MediaWiki:Gadget-Mastodon.js - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="https://schwarzatal.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-Mastodon.js"/>
	<link rel="alternate" type="text/html" href="https://schwarzatal.org/index.php?title=MediaWiki:Gadget-Mastodon.js&amp;action=history"/>
	<updated>2026-09-22T11:50:44Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Schwarzatal.org</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://schwarzatal.org/index.php?title=MediaWiki:Gadget-Mastodon.js&amp;diff=1343&amp;oldid=prev</id>
		<title>Admin: Die Seite wurde neu angelegt: „/**  * Gadget-Mastodon.js  * ============================================================================  * Bettet Mastodon-Beiträge (samt Video oder anderen Medien) in Wiki-Seiten  * ein – instanzunabhängig, also mastodon.social genauso wie jede andere  * Instanz. Verwendet die eingebaute /embed-Ansicht von Mastodon.  *  * KEIN ZUSATZSKRIPT DES ANBIETERS  * Die offizielle Einbindung lädt embed.js der Instanz nach, nur um die Höhe  * des Rahmens an…“</title>
		<link rel="alternate" type="text/html" href="https://schwarzatal.org/index.php?title=MediaWiki:Gadget-Mastodon.js&amp;diff=1343&amp;oldid=prev"/>
		<updated>2026-09-19T18:12:27Z</updated>

		<summary type="html">&lt;p&gt;Die Seite wurde neu angelegt: „/**  * Gadget-Mastodon.js  * ============================================================================  * Bettet Mastodon-Beiträge (samt Video oder anderen Medien) in Wiki-Seiten  * ein – instanzunabhängig, also mastodon.social genauso wie jede andere  * Instanz. Verwendet die eingebaute /embed-Ansicht von Mastodon.  *  * KEIN ZUSATZSKRIPT DES ANBIETERS  * Die offizielle Einbindung lädt embed.js der Instanz nach, nur um die Höhe  * des Rahmens an…“&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/**&lt;br /&gt;
 * Gadget-Mastodon.js&lt;br /&gt;
 * ============================================================================&lt;br /&gt;
 * Bettet Mastodon-Beiträge (samt Video oder anderen Medien) in Wiki-Seiten&lt;br /&gt;
 * ein – instanzunabhängig, also mastodon.social genauso wie jede andere&lt;br /&gt;
 * Instanz. Verwendet die eingebaute /embed-Ansicht von Mastodon.&lt;br /&gt;
 *&lt;br /&gt;
 * KEIN ZUSATZSKRIPT DES ANBIETERS&lt;br /&gt;
 * Die offizielle Einbindung lädt embed.js der Instanz nach, nur um die Höhe&lt;br /&gt;
 * des Rahmens anzupassen. Das macht dieses Gadget selbst: Mastodon beantwortet&lt;br /&gt;
 * eine postMessage mit seiner tatsächlichen Höhe. Es wird also genau eine&lt;br /&gt;
 * Adresse der Instanz abgerufen und sonst nichts.&lt;br /&gt;
 *&lt;br /&gt;
 * KEINE ZWEI-KLICK-SPERRE – warum nicht?&lt;br /&gt;
 * Die /embed-Ansicht ist eine öffentliche, cachebare Seite ohne Werbung,&lt;br /&gt;
 * ohne Reichweitenmessung und ohne Profilbildung; für anonyme Besucher&lt;br /&gt;
 * setzt sie keine Cookies. Damit greift die Einwilligungspflicht des&lt;br /&gt;
 * §165 TKG nicht, und für die IP-Übertragung beim Abruf trägt das&lt;br /&gt;
 * berechtigte Interesse – wie beim CCC-Gadget. Anders bei fahrplan.oebb.at&lt;br /&gt;
 * und makertube.net, die ihre Vorschaubox behalten haben.&lt;br /&gt;
 *&lt;br /&gt;
 * NOTAUSGANG: data-sperre=&amp;quot;ja&amp;quot; schaltet für eine einzelne Einbettung doch&lt;br /&gt;
 * eine Vorschaubox mit Ladeknopf davor – gedacht für Instanzen, deren&lt;br /&gt;
 * Betreiber du nicht einschätzen kannst.&lt;br /&gt;
 *&lt;br /&gt;
 * EINBINDUNG AUF EINER SEITE&lt;br /&gt;
 *   &amp;lt;div class=&amp;quot;mastodon-embed&amp;quot;&lt;br /&gt;
 *        data-post=&amp;quot;https://mastodon.social/@benutzer/123456789012345678&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * Alternativ getrennt:&lt;br /&gt;
 *   &amp;lt;div class=&amp;quot;mastodon-embed&amp;quot; data-instanz=&amp;quot;mastodon.social&amp;quot;&lt;br /&gt;
 *        data-benutzer=&amp;quot;benutzer&amp;quot; data-id=&amp;quot;123456789012345678&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 *&lt;br /&gt;
 * data-Attribute:&lt;br /&gt;
 *   data-post      Vollständige Adresse des Beitrags (empfohlen).&lt;br /&gt;
 *   data-instanz   Hostname der Instanz, falls data-post nicht genutzt wird.&lt;br /&gt;
 *   data-benutzer  Benutzername ohne @, zusammen mit data-instanz/data-id.&lt;br /&gt;
 *   data-id        Beitrags-ID, zusammen mit data-instanz/data-benutzer.&lt;br /&gt;
 *   data-width     Breite (Standard 100%, höchstens 42em).&lt;br /&gt;
 *   data-height    Starthöhe in Pixeln (Standard 600). Die endgültige Höhe&lt;br /&gt;
 *                  meldet Mastodon selbst, sobald der Beitrag geladen ist.&lt;br /&gt;
 *   data-titel     Titelzeile des Rahmens, für Screenreader&lt;br /&gt;
 *                  (Standard: &amp;quot;Mastodon-Beitrag&amp;quot;).&lt;br /&gt;
 *   data-sperre    &amp;quot;ja&amp;quot; =&amp;gt; Vorschaubox mit Ladeknopf davorschalten.&lt;br /&gt;
 * ============================================================================&lt;br /&gt;
 */&lt;br /&gt;
( function () {&lt;br /&gt;
	&amp;#039;use strict&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
	var STD_HOEHE = 600;&lt;br /&gt;
&lt;br /&gt;
	/* Laufende Rahmen für die Höhenmeldung: Kennnummer -&amp;gt; iframe */&lt;br /&gt;
	var rahmenListe = {};&lt;br /&gt;
	var naechsteNummer = 0;&lt;br /&gt;
	var hoertZu = false;&lt;br /&gt;
&lt;br /&gt;
	function stil( el, regeln ) {&lt;br /&gt;
		var name;&lt;br /&gt;
		for ( name in regeln ) {&lt;br /&gt;
			el.style[ name ] = regeln[ name ];&lt;br /&gt;
		}&lt;br /&gt;
		return el;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	function masszahl( wert, standard ) {&lt;br /&gt;
		if ( wert === undefined || wert === null || wert === &amp;#039;&amp;#039; ) {&lt;br /&gt;
			return standard;&lt;br /&gt;
		}&lt;br /&gt;
		var text = String( wert ).trim();&lt;br /&gt;
		return /^\d+$/.test( text ) ? text + &amp;#039;px&amp;#039; : text;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* ------------------------------------------------------------------ *&lt;br /&gt;
	 * Adresse des Beitrags auswerten.&lt;br /&gt;
	 * Erlaubt sind die üblichen Mastodon-Formen:&lt;br /&gt;
	 *   https://instanz/@benutzer/123…&lt;br /&gt;
	 *   https://instanz/@benutzer@andereinstanz/123…&lt;br /&gt;
	 *   https://instanz/users/benutzer/statuses/123…&lt;br /&gt;
	 * Zurück kommt { host, seite, embed } oder null.&lt;br /&gt;
	 * ------------------------------------------------------------------ */&lt;br /&gt;
	function leseAdresse( roh ) {&lt;br /&gt;
		var text = String( roh || &amp;#039;&amp;#039; ).trim();&lt;br /&gt;
		if ( !/^https:\/\//i.test( text ) ) {&lt;br /&gt;
			return null;&lt;br /&gt;
		}&lt;br /&gt;
		var a = document.createElement( &amp;#039;a&amp;#039; );&lt;br /&gt;
		a.href = text;&lt;br /&gt;
		if ( !a.hostname || a.protocol !== &amp;#039;https:&amp;#039; ) {&lt;br /&gt;
			return null;&lt;br /&gt;
		}&lt;br /&gt;
		var pfad = a.pathname.replace( /\/+$/, &amp;#039;&amp;#039; ).replace( /\/embed$/, &amp;#039;&amp;#039; );&lt;br /&gt;
		if ( !/^\/(@[^/]+\/\d+|users\/[^/]+\/statuses\/\d+)$/.test( pfad ) ) {&lt;br /&gt;
			return null;&lt;br /&gt;
		}&lt;br /&gt;
		var seite = &amp;#039;https://&amp;#039; + a.hostname + pfad;&lt;br /&gt;
		return { host: a.hostname, seite: seite, embed: seite + &amp;#039;/embed&amp;#039; };&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* ------------------------------------------------------------------ *&lt;br /&gt;
	 * Höhenmeldung von Mastodon entgegennehmen. Das eingebettete Mastodon&lt;br /&gt;
	 * antwortet auf { type: &amp;quot;setHeight&amp;quot;, id: … } mit derselben Nachricht&lt;br /&gt;
	 * samt height – so sparen wir uns das embed.js des Anbieters.&lt;br /&gt;
	 * ------------------------------------------------------------------ */&lt;br /&gt;
	function starteZuhoerer() {&lt;br /&gt;
		if ( hoertZu ) {&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		hoertZu = true;&lt;br /&gt;
		window.addEventListener( &amp;#039;message&amp;#039;, function ( e ) {&lt;br /&gt;
			var daten = e.data || {};&lt;br /&gt;
			if ( daten.type !== &amp;#039;setHeight&amp;#039; || !rahmenListe[ daten.id ] ) {&lt;br /&gt;
				return;&lt;br /&gt;
			}&lt;br /&gt;
			var hoehe = parseInt( daten.height, 10 );&lt;br /&gt;
			if ( isFinite( hoehe ) &amp;amp;&amp;amp; hoehe &amp;gt; 0 ) {&lt;br /&gt;
				rahmenListe[ daten.id ].style.height = hoehe + &amp;#039;px&amp;#039;;&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* --- Beitrag einhängen ------------------------------------------------ */&lt;br /&gt;
	function lade( container, cfg ) {&lt;br /&gt;
		container.textContent = &amp;#039;&amp;#039;;&lt;br /&gt;
		starteZuhoerer();&lt;br /&gt;
&lt;br /&gt;
		var nummer = &amp;#039;wiki-mastodon-&amp;#039; + ( naechsteNummer++ );&lt;br /&gt;
&lt;br /&gt;
		var iframe = document.createElement( &amp;#039;iframe&amp;#039; );&lt;br /&gt;
		iframe.src = cfg.embed;&lt;br /&gt;
		iframe.title = cfg.titel + &amp;#039; (&amp;#039; + cfg.host + &amp;#039;)&amp;#039;;&lt;br /&gt;
		iframe.setAttribute( &amp;#039;frameborder&amp;#039;, &amp;#039;0&amp;#039; );&lt;br /&gt;
		iframe.setAttribute( &amp;#039;scrolling&amp;#039;, &amp;#039;no&amp;#039; );&lt;br /&gt;
		iframe.setAttribute( &amp;#039;allowfullscreen&amp;#039;, &amp;#039;allowfullscreen&amp;#039; );&lt;br /&gt;
		iframe.setAttribute( &amp;#039;allow&amp;#039;, &amp;#039;fullscreen&amp;#039; );&lt;br /&gt;
		iframe.setAttribute( &amp;#039;sandbox&amp;#039;,&lt;br /&gt;
			&amp;#039;allow-same-origin allow-scripts allow-popups&amp;#039; );&lt;br /&gt;
		iframe.setAttribute( &amp;#039;loading&amp;#039;, &amp;#039;lazy&amp;#039; );&lt;br /&gt;
		iframe.setAttribute( &amp;#039;referrerpolicy&amp;#039;, &amp;#039;no-referrer&amp;#039; );&lt;br /&gt;
		stil( iframe, {&lt;br /&gt;
			width: cfg.breite,&lt;br /&gt;
			maxWidth: &amp;#039;42em&amp;#039;,&lt;br /&gt;
			height: cfg.hoehe,&lt;br /&gt;
			border: &amp;#039;0&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
&lt;br /&gt;
		rahmenListe[ nummer ] = iframe;&lt;br /&gt;
		iframe.addEventListener( &amp;#039;load&amp;#039;, function () {&lt;br /&gt;
			try {&lt;br /&gt;
				iframe.contentWindow.postMessage(&lt;br /&gt;
					{ type: &amp;#039;setHeight&amp;#039;, id: nummer }, &amp;#039;https://&amp;#039; + cfg.host&lt;br /&gt;
				);&lt;br /&gt;
			} catch ( e ) {}&lt;br /&gt;
		} );&lt;br /&gt;
&lt;br /&gt;
		container.appendChild( iframe );&lt;br /&gt;
&lt;br /&gt;
		// Rückfallebene: wer das iframe blockiert, bekommt wenigstens den Weg&lt;br /&gt;
		// zum Beitrag.&lt;br /&gt;
		var fuss = stil( document.createElement( &amp;#039;div&amp;#039; ), {&lt;br /&gt;
			fontSize: &amp;#039;85%&amp;#039;,&lt;br /&gt;
			color: &amp;#039;#54595d&amp;#039;,&lt;br /&gt;
			marginTop: &amp;#039;0.4em&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
		var link = document.createElement( &amp;#039;a&amp;#039; );&lt;br /&gt;
		link.href = cfg.seite;&lt;br /&gt;
		link.target = &amp;#039;_blank&amp;#039;;&lt;br /&gt;
		link.rel = &amp;#039;noopener&amp;#039;;&lt;br /&gt;
		link.textContent = &amp;#039;Beitrag auf &amp;#039; + cfg.host + &amp;#039; öffnen&amp;#039;;&lt;br /&gt;
		fuss.appendChild( link );&lt;br /&gt;
		container.appendChild( fuss );&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* --- Notausgang: Vorschaubox statt sofortigem Laden -------------------- */&lt;br /&gt;
	function sperre( container, cfg ) {&lt;br /&gt;
		container.textContent = &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
		var box = stil( document.createElement( &amp;#039;div&amp;#039; ), {&lt;br /&gt;
			border: &amp;#039;1px solid #a2a9b1&amp;#039;,&lt;br /&gt;
			borderRadius: &amp;#039;2px&amp;#039;,&lt;br /&gt;
			background: &amp;#039;#f8f9fa&amp;#039;,&lt;br /&gt;
			padding: &amp;#039;1em&amp;#039;,&lt;br /&gt;
			maxWidth: &amp;#039;42em&amp;#039;,&lt;br /&gt;
			boxSizing: &amp;#039;border-box&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
		box.className = &amp;#039;mastodon-embed-sperre&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
		var kopf = stil( document.createElement( &amp;#039;div&amp;#039; ), {&lt;br /&gt;
			fontWeight: &amp;#039;bold&amp;#039;,&lt;br /&gt;
			fontSize: &amp;#039;108%&amp;#039;,&lt;br /&gt;
			marginBottom: &amp;#039;0.4em&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
		kopf.textContent = cfg.titel + &amp;#039; von &amp;#039; + cfg.host;&lt;br /&gt;
		box.appendChild( kopf );&lt;br /&gt;
&lt;br /&gt;
		var text = stil( document.createElement( &amp;#039;p&amp;#039; ), { margin: &amp;#039;0.4em 0&amp;#039; } );&lt;br /&gt;
		text.textContent = &amp;#039;Der Beitrag wird direkt von der Mastodon-Instanz &amp;#039; +&lt;br /&gt;
			cfg.host + &amp;#039; geladen – einem Server, der nicht uns gehört. Dabei &amp;#039; +&lt;br /&gt;
			&amp;#039;erfährt dessen Betreiber deine IP-Adresse und welchen Beitrag du &amp;#039; +&lt;br /&gt;
			&amp;#039;ansiehst. Vor deinem Klick geht keine Anfrage dorthin.&amp;#039;;&lt;br /&gt;
		box.appendChild( text );&lt;br /&gt;
&lt;br /&gt;
		var knopf = stil( document.createElement( &amp;#039;button&amp;#039; ), {&lt;br /&gt;
			cursor: &amp;#039;pointer&amp;#039;,&lt;br /&gt;
			padding: &amp;#039;0.4em 0.9em&amp;#039;,&lt;br /&gt;
			fontWeight: &amp;#039;bold&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
		knopf.type = &amp;#039;button&amp;#039;;&lt;br /&gt;
		knopf.textContent = &amp;#039;Beitrag laden&amp;#039;;&lt;br /&gt;
		knopf.addEventListener( &amp;#039;click&amp;#039;, function () {&lt;br /&gt;
			lade( container, cfg );&lt;br /&gt;
		} );&lt;br /&gt;
		box.appendChild( stil( document.createElement( &amp;#039;div&amp;#039; ),&lt;br /&gt;
			{ margin: &amp;#039;0.7em 0&amp;#039; } ) ).appendChild( knopf );&lt;br /&gt;
&lt;br /&gt;
		var fuss = stil( document.createElement( &amp;#039;div&amp;#039; ), {&lt;br /&gt;
			fontSize: &amp;#039;85%&amp;#039;,&lt;br /&gt;
			color: &amp;#039;#54595d&amp;#039;,&lt;br /&gt;
			marginTop: &amp;#039;0.6em&amp;#039;&lt;br /&gt;
		} );&lt;br /&gt;
		var link = document.createElement( &amp;#039;a&amp;#039; );&lt;br /&gt;
		link.href = cfg.seite;&lt;br /&gt;
		link.target = &amp;#039;_blank&amp;#039;;&lt;br /&gt;
		link.rel = &amp;#039;noopener&amp;#039;;&lt;br /&gt;
		link.textContent = &amp;#039;Stattdessen direkt auf &amp;#039; + cfg.host + &amp;#039; ansehen&amp;#039;;&lt;br /&gt;
		fuss.appendChild( link );&lt;br /&gt;
		box.appendChild( fuss );&lt;br /&gt;
&lt;br /&gt;
		container.appendChild( box );&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* --- Einstieg ---------------------------------------------------------- */&lt;br /&gt;
	function baueEinbettung( container ) {&lt;br /&gt;
		var $c = $( container );&lt;br /&gt;
		var roh = $.trim( String( $c.data( &amp;#039;post&amp;#039; ) || &amp;#039;&amp;#039; ) );&lt;br /&gt;
&lt;br /&gt;
		if ( !roh ) {&lt;br /&gt;
			var instanz = $.trim( String( $c.data( &amp;#039;instanz&amp;#039; ) || &amp;#039;&amp;#039; ) )&lt;br /&gt;
				.replace( /^https?:\/\//i, &amp;#039;&amp;#039; ).replace( /\/+$/, &amp;#039;&amp;#039; );&lt;br /&gt;
			var benutzer = $.trim( String( $c.data( &amp;#039;benutzer&amp;#039; ) || &amp;#039;&amp;#039; ) )&lt;br /&gt;
				.replace( /^@/, &amp;#039;&amp;#039; );&lt;br /&gt;
			var id = $.trim( String( $c.data( &amp;#039;id&amp;#039; ) || &amp;#039;&amp;#039; ) );&lt;br /&gt;
			if ( instanz &amp;amp;&amp;amp; benutzer &amp;amp;&amp;amp; id ) {&lt;br /&gt;
				roh = &amp;#039;https://&amp;#039; + instanz + &amp;#039;/@&amp;#039; + benutzer + &amp;#039;/&amp;#039; + id;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var adresse = leseAdresse( roh );&lt;br /&gt;
		if ( !adresse ) {&lt;br /&gt;
			container.textContent = &amp;#039;Mastodon-Einbettung: keine gültige &amp;#039; +&lt;br /&gt;
				&amp;#039;Beitragsadresse angegeben (erwartet z. B. &amp;#039; +&lt;br /&gt;
				&amp;#039;https://mastodon.social/@benutzer/123456789012345678).&amp;#039;;&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		var cfg = {&lt;br /&gt;
			host: adresse.host,&lt;br /&gt;
			seite: adresse.seite,&lt;br /&gt;
			embed: adresse.embed,&lt;br /&gt;
			titel: $.trim( String( $c.data( &amp;#039;titel&amp;#039; ) || &amp;#039;&amp;#039; ) ) || &amp;#039;Mastodon-Beitrag&amp;#039;,&lt;br /&gt;
			breite: masszahl( $c.data( &amp;#039;width&amp;#039; ), &amp;#039;100%&amp;#039; ),&lt;br /&gt;
			hoehe: masszahl( $c.data( &amp;#039;height&amp;#039; ), STD_HOEHE + &amp;#039;px&amp;#039; )&lt;br /&gt;
		};&lt;br /&gt;
&lt;br /&gt;
		if ( String( $c.data( &amp;#039;sperre&amp;#039; ) || &amp;#039;&amp;#039; ) === &amp;#039;ja&amp;#039; ) {&lt;br /&gt;
			sperre( container, cfg );&lt;br /&gt;
		} else {&lt;br /&gt;
			lade( container, cfg );&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	$( function () {&lt;br /&gt;
		$( &amp;#039;.mastodon-embed&amp;#039; ).each( function () {&lt;br /&gt;
			try {&lt;br /&gt;
				baueEinbettung( this );&lt;br /&gt;
			} catch ( e ) {&lt;br /&gt;
				this.textContent = &amp;#039;Mastodon-Beitrag konnte nicht geladen werden.&amp;#039;;&lt;br /&gt;
				if ( window.mw &amp;amp;&amp;amp; mw.log ) {&lt;br /&gt;
					mw.log.error( e );&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
		} );&lt;br /&gt;
	} );&lt;br /&gt;
&lt;br /&gt;
}() );&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>