|
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 | + return 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 | + setInterval(updateIframeHeight, 1000); // the easiest way to handle dynamic content changes and easy to debug, can be fine-tuned in the future |
| 24 | + |
| 25 | + // no way to open an absolute link with CSP frame-src, it also needs some tricks like "postMessage" or "copy the link to clipboard" |
| 26 | + const openIframeLink = (link: string, target: string) => postIframeMsg('open-link', {openLink: link, anchorTarget: target}); |
| 27 | + document.addEventListener('click', (e) => { |
24 | 28 | const el = e.target as HTMLAnchorElement; |
25 | 29 | if (el.nodeName !== 'A') return; |
26 | | - const href = el.getAttribute('href'); |
27 | | - if (!href.startsWith('//') && !href.includes('://')) return; |
28 | | - el.target = '_blank'; |
29 | | - }, true); |
| 30 | + const href = el.getAttribute('href') || ''; |
| 31 | + // safe links: "./any", "../any", "/any", "//host/any", "http://host/any", "https://host/any" |
| 32 | + if (href.startsWith('.') || href.startsWith('/') || href.startsWith('http://') || href.startsWith('https://')) { |
| 33 | + e.preventDefault(); |
| 34 | + openIframeLink(href, el.getAttribute('target')); |
| 35 | + } |
| 36 | + }); |
30 | 37 | } |
31 | 38 |
|
32 | 39 | mainExternalRenderIframe(); |
0 commit comments