ich habe mir das Thema nochmal angeschaut und denke eine Lösung für das Einbinden von Toot's gefunden zu haben. Sprich ich habe da selber etwas gebaut. Soll ich das ins Forum einbauen? Ich habe bisher erstmal nur einen PoC (Proof of Concept) erstellt, ob das überhaupt irgendwie geht.
Es müsste da aber noch ein wenig Arbeit reingesteckt werden, dass das dann aus einem BB-Code einen eingebetteten Toot macht. Außerdem ist da ziemlich viel Javascript notwendig
Hier ist der Code von meinem PoC:
Code: Alles auswählen
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mastodon oembed test</title>
<style>
.mastodon-embed {
display: block;
margin: 10px 0;
}
</style>
</head>
<body>
<div>
<input type="text" name="toot" class="js-mastodon-input" />
<input type="button" id="embed" value="Einbinden" />
</div>
<div class="js-mastodon-embed-container"></div>
<script async="async">
const iframes = new Map();
const $container = document.querySelector(".js-mastodon-embed-container");
const mastodonUrlMatcher = /(https?:\/\/[^/]*)\/@[^@/]*\/[^?/]*/g;
const isValidUrl = (candidate) => {
let url;
try {
url = new URL(candidate);
} catch (_) {
return false;
}
return url.protocol === "http:" || url.protocol === "https:";
};
const htmlToIframeElement = (html) => {
if (!html) return;
const template = document.createElement("template");
template.innerHTML = html.trim();
// we only want the iframe and not the embedded script tag
return template.content.firstChild;
};
const getNewId = () => {
let id = 0;
let failCount = 0;
let idBuffer = new Uint32Array(1);
while (id === 0 || iframes.has(id)) {
id = crypto.getRandomValues(idBuffer)[0];
failCount++;
if (failCount > 100) {
// give up and assign (easily guessable) unique number if getRandomValues is broken or no luck
id = -(iframes.size + 1);
break;
}
}
return id;
};
const setHeightMessageHandler = (e) => {
const data = e.data || {};
if (
typeof data !== "object" ||
data.type !== "setHeight" ||
!iframes.has(data.id)
) {
return;
}
const iframe = iframes.get(data.id);
if ("source" in e && iframe.contentWindow !== e.source) {
return;
}
iframe.height = data.height;
};
const embedToot = async (toot) => {
if (!isValidUrl(toot)) {
return;
}
const matchedUrlParts = mastodonUrlMatcher.exec(toot);
if (!matchedUrlParts || matchedUrlParts.length !== 2) {
return;
}
const [mastodonTootUrl, instanceUrl] = matchedUrlParts;
const response = await fetch(
`${instanceUrl}/api/oembed?url=${mastodonTootUrl}&maxwidth=550`
);
if (response.status !== 200) {
return;
}
const responseJson = await response.json();
const iframe = htmlToIframeElement(responseJson.html);
const id = getNewId();
iframes.set(id, iframe);
iframe.scrolling = "no";
iframe.style.overflow = "hidden";
iframe.onload = function () {
iframe.contentWindow.postMessage(
{
type: "setHeight",
id: id,
},
"*"
);
};
$container.append(iframe);
};
window.addEventListener("message", setHeightMessageHandler);
</script>
<script async="async">
const $toot = document.querySelector(".js-mastodon-input");
const $embed = document.getElementById("embed");
if ($toot && $embed) {
$embed.addEventListener("click", () => {
embedToot($toot.value);
});
}
</script>
</body>
</html>