// External render JS must be a IIFE module to run as early as possible to set up the environment for the content page. // Avoid unnecessary dependency. // Do NOT introduce global pollution, because the content page should be fully controlled by the external render. /* To manually test: [markup.in-iframe] ENABLED = true FILE_EXTENSIONS = .in-iframe RENDER_CONTENT_MODE = iframe RENDER_COMMAND = `echo '
'` ;RENDER_COMMAND = cat /path/to/file.pdf ;RENDER_CONTENT_SANDBOX = disabled */ // Check whether the user-provided color value is a valid CSS color format to avoid CSS injection. // Don't extract this function to a common module, because this file is an IIFE module for external render // and should not have any dependency to avoid potential conflicts. function isValidCssColor(s: string | null): boolean { if (!s) return false; // it should only be in format "#hex" or "rgb(...)", because it comes from a computed style's color value const reHex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/; const reRgb = /^rgb\([^{}'";:]+\)$/; return reHex.test(s) || reRgb.test(s); } const thisScriptElem = document.querySelector('script#gitea-external-render-helper'); const queryString = thisScriptElem?.getAttribute('data-render-query-string') ?? window.location.search.substring(1); const queryParams = new URLSearchParams(queryString); const isDarkTheme = queryParams.get('gitea-is-dark-theme') === 'true'; if (isDarkTheme) { document.documentElement.setAttribute('data-gitea-theme-dark', String(isDarkTheme)); } const backgroundColor = queryParams.get('gitea-iframe-bgcolor'); if (isValidCssColor(backgroundColor)) { // create a style element to set background color, then it can be overridden by the content page's own style if needed const style = document.createElement('style'); style.textContent = ` :root { --gitea-iframe-bgcolor: ${backgroundColor}; } html, body { margin: 0; padding: 0 } body { background: ${backgroundColor}; } `; document.head.append(style); } const iframeId = queryParams.get('gitea-iframe-id'); if (iframeId) { // iframe is in different origin, so we need to use postMessage to communicate const postIframeMsg = (cmd: string, data: Record