Add coordinated blog iframe resize messaging

This commit is contained in:
thePR0M3TH3AN committed 2025-10-17 11:32:25 -04:00
1 parent a76326eacf
commit 60cf6bb9c1
2 files changed
+166

No files matched your search

+71
View File
@@ -132,6 +132,76 @@ function resolveNotes() {
return buildDefaultNotes();
}
function setupEmbedHeightBroadcast({ root, registerCleanup }) {
if (typeof window === 'undefined' || !root || window.parent === window) {
return;
}
const parentOrigin = (() => {
try {
if (document.referrer) {
return new URL(document.referrer).origin;
}
} catch (error) {
userLogger.error('[blog] failed to parse parent origin for resize messaging', error);
}
return '*';
})();
let lastHeight = null;
const postHeight = (force = false) => {
const rect = root.getBoundingClientRect();
const height = Math.ceil(rect.height);
if (!Number.isFinite(height) || height < 0) {
return;
}
if (!force && height === lastHeight) {
return;
}
lastHeight = height;
try {
window.parent.postMessage({ type: 'bitvid-blog-resize', height }, parentOrigin);
} catch (error) {
userLogger.error('[blog] failed to post resize message', error);
}
};
const rafId = window.requestAnimationFrame(() => {
postHeight();
});
registerCleanup(() => {
window.cancelAnimationFrame(rafId);
});
if (typeof ResizeObserver === 'function') {
const observer = new ResizeObserver(() => {
postHeight();
});
observer.observe(root);
registerCleanup(() => {
observer.disconnect();
});
}
const handleMessage = (event) => {
if (event.source !== window.parent) {
return;
}
if (parentOrigin !== '*' && event.origin !== parentOrigin) {
return;
}
if (event?.data?.type === 'bitvid-blog-request-height') {
postHeight(true);
}
};
window.addEventListener('message', handleMessage);
registerCleanup(() => {
window.removeEventListener('message', handleMessage);
});
}
function formatDate(unixSeconds, { includeTime = false } = {}) {
if (!unixSeconds) {
return '';
@@ -724,6 +794,7 @@ function mountBlogApp({ initZapthreadsEmbed = defaultInitZapthreadsEmbed } = {})
}
root.replaceChildren(main);
setupEmbedHeightBroadcast({ root, registerCleanup });
registerCleanup(() => {
root.replaceChildren();
+95
View File
@@ -11,6 +11,101 @@
src="https://beta.bitvid.network/blog.html"
class="h-full w-full border-none"
></iframe>
<script type="module">
const iframe = document.querySelector('#blog-iframe');
if (iframe) {
const abortController = new AbortController();
const { signal } = abortController;
const targetOrigin = (() => {
try {
return new URL(iframe.src, window.location.href).origin;
} catch (error) {
return window.location.origin;
}
})();
const applyHeight = (height) => {
const numeric = Math.max(0, Math.round(Number(height)));
if (!Number.isFinite(numeric)) {
return;
}
iframe.style.height = `${numeric}px`;
iframe.style.removeProperty('min-height');
iframe.style.removeProperty('max-height');
};
const handleMessage = (event) => {
if (event.source !== iframe.contentWindow) {
return;
}
if (event.origin !== targetOrigin) {
return;
}
if (event.data?.type === 'bitvid-blog-resize') {
applyHeight(event.data.height);
}
};
window.addEventListener('message', handleMessage, { signal });
const requestHeight = () => {
if (!iframe.contentWindow) {
return;
}
iframe.contentWindow.postMessage(
{ type: 'bitvid-blog-request-height' },
targetOrigin,
);
};
const startRetryLoop = () => {
const maxAttempts = 5;
let attempts = 0;
const retryIntervalMs = 200;
const intervalId = window.setInterval(() => {
attempts += 1;
if (attempts > maxAttempts) {
window.clearInterval(intervalId);
return;
}
requestHeight();
}, retryIntervalMs);
const stop = () => {
window.clearInterval(intervalId);
};
if (signal.aborted) {
stop();
} else {
signal.addEventListener('abort', stop, { once: true });
}
};
const runInitialRequests = () => {
requestHeight();
startRetryLoop();
};
iframe.addEventListener('load', () => {
runInitialRequests();
}, { signal });
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', runInitialRequests, {
once: true,
signal,
});
} else {
runInitialRequests();
}
window.addEventListener('pagehide', () => {
abortController.abort();
}, { once: true });
}
</script>
</div>
</div>
</article>