fix: use scrollHeight for rendered iframe if offsetHeight is unavailable (#9508)
Fixes #9421. Added integration test. Co-authored-by: Gusted <postmaster@gusted.xyz> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/9508 Reviewed-by: Gusted <gusted@noreply.codeberg.org> Reviewed-by: Michael Kriese <michael.kriese@gmx.de> Co-authored-by: Bojidar Marinov <bojidar.marinov.bg@gmail.com> Co-committed-by: Bojidar Marinov <bojidar.marinov.bg@gmail.com>
This commit is contained in:
committed by
Gusted
co-authored by
Gusted
parent
e56fdf1ec5
commit
8ed95dc4c6
@@ -1921,4 +1921,3 @@
|
||||
is_fsck_enabled: true
|
||||
close_issues_via_commit_in_any_branch: false
|
||||
topics: '[]'
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr
|
||||
if r, ok := renderer.(ExternalRenderer); ok && r.DisplayInIFrame() {
|
||||
// Append a short script to the iframe's contents, which will communicate the scroll height of the embedded document via postMessage, either once loaded (in case the containing page loads first) in response to a postMessage from external.js, in case the iframe loads first
|
||||
// We use '*' as a target origin for postMessage, because can be certain we are embedded on the same domain, due to X-Frame-Options configured elsewhere. (Plus, the offsetHeight of an embedded document is likely not sensitive data anyway.)
|
||||
_, _ = pw.Write([]byte("<script>{let postHeight = () => {window.parent.postMessage({frameHeight: document.documentElement.offsetHeight}, '*')}; window.addEventListener('load', postHeight); window.addEventListener('message', (event) => {if (event.source === window.parent && event.data.requestOffsetHeight) postHeight()});}</script>"))
|
||||
_, _ = pw.Write([]byte("<script>{let postHeight = () => {window.parent.postMessage({frameHeight: document.documentElement.offsetHeight || document.documentElement.scrollHeight}, '*')}; window.addEventListener('load', postHeight); window.addEventListener('message', (event) => {if (event.source === window.parent && event.data.requestOffsetHeight) postHeight()});}</script>"))
|
||||
}
|
||||
_ = pw.Close()
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ func TestCheckUnadoptedRepositories(t *testing.T) {
|
||||
func TestListUnadoptedRepositories_ListOptions(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
username := "user2"
|
||||
unadoptedList := []string{path.Join(username, "unadopted1"), path.Join(username, "unadopted2")}
|
||||
unadoptedList := []string{path.Join(username, "rendering-test"), path.Join(username, "unadopted1"), path.Join(username, "unadopted2")}
|
||||
for _, unadopted := range unadoptedList {
|
||||
_ = os.Mkdir(path.Join(setting.RepoRootPath, unadopted+".git"), 0o755)
|
||||
}
|
||||
@@ -77,13 +77,13 @@ func TestListUnadoptedRepositories_ListOptions(t *testing.T) {
|
||||
opts := db.ListOptions{Page: 1, PageSize: 1}
|
||||
repoNames, count, err := ListUnadoptedRepositories(db.DefaultContext, "", &opts)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, count)
|
||||
assert.Equal(t, 3, count)
|
||||
assert.Equal(t, unadoptedList[0], repoNames[0])
|
||||
|
||||
opts = db.ListOptions{Page: 2, PageSize: 1}
|
||||
repoNames, count, err = ListUnadoptedRepositories(db.DefaultContext, "", &opts)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, count)
|
||||
assert.Equal(t, 3, count)
|
||||
assert.Equal(t, unadoptedList[1], repoNames[0])
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func TestAdoptRepository(t *testing.T) {
|
||||
path.Join(setting.RepoRootPath, username, unadopted+".git"),
|
||||
))
|
||||
|
||||
opts := db.ListOptions{Page: 1, PageSize: 1}
|
||||
opts := db.ListOptions{Page: 2, PageSize: 1}
|
||||
repoNames, _, err := ListUnadoptedRepositories(db.DefaultContext, "", &opts)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, repoNames, path.Join(username, unadopted))
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
-
|
||||
id: 1001
|
||||
repo_id: 1002
|
||||
type: 1
|
||||
config: "{}"
|
||||
created_unix: 946684810
|
||||
@@ -11,3 +11,18 @@
|
||||
status: 0
|
||||
lfs_size: 8192
|
||||
topics: '[]'
|
||||
|
||||
|
||||
-
|
||||
id: 1002
|
||||
owner_id: 2
|
||||
owner_name: user2
|
||||
lower_name: rendering-test
|
||||
name: rendering-test
|
||||
default_branch: master
|
||||
is_empty: false
|
||||
is_archived: false
|
||||
is_private: false
|
||||
status: 0
|
||||
num_issues: 0
|
||||
topics: '[]'
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// @watch start
|
||||
// web_src/js/markup/external.js
|
||||
// @watch end
|
||||
|
||||
import {expect} from '@playwright/test';
|
||||
import {test} from './utils_e2e.ts';
|
||||
|
||||
test('iframe renderer shrinks to shorter page', async ({page}, _workerInfo) => {
|
||||
const previewPath = '/user2/rendering-test/src/branch/master/short.iframehtml';
|
||||
|
||||
const response = await page.goto(previewPath, {waitUntil: 'domcontentloaded'});
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
const preview = page.locator('iframe.external-render');
|
||||
await expect.poll(async () => {
|
||||
const boundingBox = await preview.boundingBox();
|
||||
return boundingBox.height;
|
||||
}).toBeLessThan(300);
|
||||
});
|
||||
|
||||
test('iframe renderer expands to taller page', async ({page}, _workerInfo) => {
|
||||
const previewPath = '/user2/rendering-test/src/branch/master/tall.iframehtml';
|
||||
|
||||
const response = await page.goto(previewPath, {waitUntil: 'domcontentloaded'});
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
const preview = page.locator('iframe.external-render');
|
||||
await expect.poll(async () => {
|
||||
const boundingBox = await preview.boundingBox();
|
||||
return boundingBox.height;
|
||||
}).toBeGreaterThan(300);
|
||||
});
|
||||
|
||||
test('iframe renderer expands to taller page with absolutely-positioned body', async ({page}, _workerInfo) => {
|
||||
const previewPath = '/user2/rendering-test/src/branch/master/absolute.iframehtml';
|
||||
|
||||
const response = await page.goto(previewPath, {waitUntil: 'domcontentloaded'});
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
const preview = page.locator('iframe.external-render');
|
||||
await expect.poll(async () => {
|
||||
const boundingBox = await preview.boundingBox();
|
||||
return boundingBox.height;
|
||||
}).toBeGreaterThan(300);
|
||||
});
|
||||
|
||||
test('iframe renderer remains at default height if script breaks', async ({page}, _workerInfo) => {
|
||||
const previewPath = '/user2/rendering-test/src/branch/master/fail.iframehtml';
|
||||
|
||||
const response = await page.goto(previewPath, {waitUntil: 'domcontentloaded'});
|
||||
expect(response?.status()).toBe(200);
|
||||
|
||||
const preview = page.locator('iframe.external-render');
|
||||
await expect.poll(async () => {
|
||||
const boundingBox = await preview.boundingBox();
|
||||
return boundingBox.height;
|
||||
}).toBeCloseTo(300, 0.5);
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
||||
@@ -0,0 +1,4 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
||||
@@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
@@ -0,0 +1,6 @@
|
||||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
x+)JMU047g040031QHL*но)-IукL+JлMм(имa╦u╖┼-ЩR╨Эеmгv4ЗЩWqь╪ш╙<-13Y╘iЛ?∙и=ЖlK▌╡В/чo⌠z╟╕╙╢8#©╗Y╜Qж╣*rO?тЬ-s╗тo╧ЕUF╗з▓дc╥_J~!\Бx╖Л{╓÷iо√:иsУсK
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
fafaad77cb54665ac800d1bf77e6a55bd355eabc
|
||||
@@ -125,3 +125,11 @@ ENABLED = false
|
||||
|
||||
[cron.check_repo_stats]
|
||||
ENABLED = false
|
||||
|
||||
# For iframe rendering tests
|
||||
[markup.iframehtml]
|
||||
ENABLED = true
|
||||
FILE_EXTENSIONS = .iframehtml
|
||||
RENDER_COMMAND = cat
|
||||
RENDER_CONTENT_MODE = iframe
|
||||
NEED_POSTPROCESS = false
|
||||
|
||||
@@ -139,3 +139,11 @@ ENABLED = false
|
||||
|
||||
[cron.check_repo_stats]
|
||||
ENABLED = false
|
||||
|
||||
# For iframe rendering tests
|
||||
[markup.iframehtml]
|
||||
ENABLED = true
|
||||
FILE_EXTENSIONS = .iframehtml
|
||||
RENDER_COMMAND = cat
|
||||
RENDER_CONTENT_MODE = iframe
|
||||
NEED_POSTPROCESS = false
|
||||
|
||||
@@ -126,3 +126,11 @@ ENABLED = false
|
||||
|
||||
[cron.check_repo_stats]
|
||||
ENABLED = false
|
||||
|
||||
# For iframe rendering tests
|
||||
[markup.iframehtml]
|
||||
ENABLED = true
|
||||
FILE_EXTENSIONS = .iframehtml
|
||||
RENDER_COMMAND = cat
|
||||
RENDER_CONTENT_MODE = iframe
|
||||
NEED_POSTPROCESS = false
|
||||
|
||||
Reference in New Issue
Block a user