';
};
if (processor == Processor.Twitter) {
const m = html.match(/https:\/\/(?:twitter\.com|x\.com)\/\w+\/status\/(\d+)/);
if (m) {
const theme = param.theme == 'dark' ? 'dark' : 'light';
html = ``;
win.on('message.twitter', (e) => {
const d = e.originalEvent.data;
if (!d || !d['twttr.embed']) return;
const msg = d['twttr.embed'];
if ((msg.method == 'twttr.private.resize') && msg.params && msg.params.length) {
const h = msg.params[0] && msg.params[0].height;
if (h) {
root.find('iframe').css({ height: h });
resize();
};
};
});
};
};
if (insertBeforeLoad) {
insertHtml(html);
};
if (processor == Processor.Youtube) {
window.onYouTubeIframeAPIReady = () => {
player = new YT.Player('player', {
events: {
onReady,
onStateChange,
}
});
};
const onReady = (event) => {
};
const onStateChange = (event) => {
};
};
loadLibs(libs, () => {
if (!insertBeforeLoad) {
insertHtml(html);
};
if (js) {
try {
eval(js);
} catch (e) {
console.error(e);
};
};
resize();
});
};
});
win.on('resize', resize);
function resize () {
const h = useRootHeight ? root.height() : document.documentElement.scrollHeight;
height = isMiniApp ? Math.max(height, h) : h;
window.parent.postMessage({ type: 'resize', height, blockId }, '*');
};
function insertHtml (html) {
if (cachedHtml !== html) {
root.html(html);
cachedHtml = html;
renderLinks();
};
};
function loadLibs (list, callBack) {
if (!list.length) {
callBack?.();
return;
};
const src = list.shift();
const script = document.createElement('script');
scripts.append(script);
script.onload = function (e) {
if (list.length) {
loadLibs(list, callBack);
} else {
callBack?.();
};
};
script.type = 'text/javascript';
script.src = src;
};
function getParam () {
const p = {};
try {
const u = new URL(location.href);
if (u.searchParams) {
u.searchParams.forEach((v, k) => p[k] = v);
};
} catch (e) {
console.error(e);
};
return p;
};
function loadGithubGist (html) {
const m = html.match(/src="([^"]+)"/);
if (!m || (m.length < 1)) {
return;
};
$.ajax({
url: m[1].replace(/\.js$/, '.json'),
dataType: 'jsonp',
timeout: 1000,
success: (data) => {
if (!head.find('#gist-css').length) {
head.append(``);
};
root.html(data.div);
renderLinks();
resize();
}
});
};
let lastInjectedAppHtml = null;
function setupAnytypeApi () {
// Outbound bridge: React calls window.__ANYTYPE_API__.setState(next)
// to push a new state to the host. Anytype writes it into the JSON
// sibling block; on the echo back the state-only path runs and
// dispatches an 'anytype:state' CustomEvent, which the React app
// listens to and uses to update its local mirror state.
//
// IMPORTANT: the React app's 'anytype:state' listener must NOT
// call setState() — it should only update its local React state.
// That's the structural rule that prevents echo loops.
window.__ANYTYPE_API__ = {
setState: function (nextState) {
window.parent.postMessage({
type: 'anytypeMiniAppState',
state: nextState,
blockId: blockId,
}, '*');
},
};
};
function injectAnytypeMiniApp (payload) {
const html = String((payload && payload.html) || '');
const state = (payload && payload.state) !== undefined ? payload.state : null;
// State-only fast path: html unchanged → don't tear down React.
// Just update window.__ANYTYPE_STATE__ and dispatch an event so
// the user's React app can update its local state without losing
// scroll position, focus, or any non-canonical UI state.
if (html === lastInjectedAppHtml) {
window.__ANYTYPE_STATE__ = state;
window.dispatchEvent(new CustomEvent('anytype:state', { detail: state }));
return;
};
// Full re-inject: html changed (first load, or user edited the
// html code block). Reset max height so the new content
// measures fresh.
height = 0;
lastInjectedAppHtml = html;
window.__ANYTYPE_STATE__ = state;
setupAnytypeApi();
// Wipe previous content + scripts so re-injects start clean.
scripts.html('');
root.empty();
if (!html) {
return;
};
// Parse the HTML in a detached div so we can extract