| 
4 | 4 | ENABLED = true  | 
5 | 5 | FILE_EXTENSIONS = .in-iframe  | 
6 | 6 | RENDER_CONTENT_MODE = iframe  | 
7 |  | -RENDER_COMMAND = `echo '<div style="width: 100%; height: 2000px; border: 10px solid red; box-sizing: border-box;">content</div>'`  | 
 | 7 | +RENDER_COMMAND = `echo '<div style="width: 100%; height: 2000px; border: 10px solid red; box-sizing: border-box;"><a href="/">a link</a> <a target="_blank" href="//gitea.com">external link</a></div>'`  | 
8 | 8 | 
  | 
9 | 9 | */  | 
10 | 10 | 
 
  | 
11 | 11 | function mainExternalRenderIframe() {  | 
12 | 12 |   const u = new URL(window.location.href);  | 
13 |  | -  const fn = () => window.parent.postMessage({  | 
14 |  | -    giteaIframeCmd: 'resize',  | 
15 |  | -    giteaIframeId: u.searchParams.get('gitea-iframe-id'),  | 
16 |  | -    giteaIframeHeight: document.documentElement.scrollHeight,  | 
17 |  | -  }, '*');  | 
18 |  | -  fn();  | 
19 |  | -  window.addEventListener('DOMContentLoaded', fn);  | 
20 |  | -  setInterval(fn, 1000);  | 
 | 13 | +  const iframeId = u.searchParams.get('gitea-iframe-id');  | 
21 | 14 | 
 
  | 
22 |  | -  // make all absolute links open in new window (otherwise they would be blocked by all parents' frame-src)  | 
23 |  | -  document.body.addEventListener('click', (e) => {  | 
 | 15 | +  // iframe is in different origin, so we need to use postMessage to communicate  | 
 | 16 | +  const postIframeMsg = (cmd: string, data: Record<string, any> = {}) => {  | 
 | 17 | +    window.parent.postMessage({giteaIframeCmd: cmd, giteaIframeId: iframeId, ...data}, '*');  | 
 | 18 | +  };  | 
 | 19 | + | 
 | 20 | +  const updateIframeHeight = () => postIframeMsg('resize', {iframeHeight: document.documentElement.scrollHeight});  | 
 | 21 | +  updateIframeHeight();  | 
 | 22 | +  window.addEventListener('DOMContentLoaded', updateIframeHeight);  | 
 | 23 | +  // the easiest way to handle dynamic content changes and easy to debug, can be fine-tuned in the future  | 
 | 24 | +  setInterval(updateIframeHeight, 1000);  | 
 | 25 | + | 
 | 26 | +  //  no way to open an absolute link with CSP frame-src, it also needs some tricks like "postMessage" or "copy the link to clipboard"  | 
 | 27 | +  const openIframeLink = (link: string, target: string) => postIframeMsg('open-link', {openLink: link, anchorTarget: target});  | 
 | 28 | +  document.addEventListener('click', (e) => {  | 
24 | 29 |     const el = e.target as HTMLAnchorElement;  | 
25 | 30 |     if (el.nodeName !== 'A') return;  | 
26 |  | -    const href = el.getAttribute('href');  | 
27 |  | -    if (!href.startsWith('//') && !href.includes('://')) return;  | 
28 |  | -    el.target = '_blank';  | 
29 |  | -  }, true);  | 
 | 31 | +    const href = el.getAttribute('href') || '';  | 
 | 32 | +    // safe links: "./any", "../any", "/any", "//host/any", "http://host/any", "https://host/any"  | 
 | 33 | +    if (href.startsWith('.') || href.startsWith('/') || href.startsWith('http://') || href.startsWith('https://')) {  | 
 | 34 | +      e.preventDefault();  | 
 | 35 | +      openIframeLink(href, el.getAttribute('target'));  | 
 | 36 | +    }  | 
 | 37 | +  });  | 
30 | 38 | }  | 
31 | 39 | 
 
  | 
32 | 40 | mainExternalRenderIframe();  | 
0 commit comments