diff --git a/src/observers/form_submit_observer.ts b/src/observers/form_submit_observer.ts index 0d3443c5c..b4b96b69a 100644 --- a/src/observers/form_submit_observer.ts +++ b/src/observers/form_submit_observer.ts @@ -35,14 +35,31 @@ export class FormSubmitObserver { const form = event.target instanceof HTMLFormElement ? event.target : undefined const submitter = event.submitter || undefined - if (form) { - const method = submitter?.getAttribute("formmethod") || form.getAttribute("method") - - if (method != "dialog" && this.delegate.willSubmitForm(form, submitter)) { - event.preventDefault() - this.delegate.formSubmitted(form, submitter) - } + if ( + form && + submissionDoesNotDismissDialog(form, submitter) && + submissionDoesNotTargetIFrame(form, submitter) && + this.delegate.willSubmitForm(form, submitter) + ) { + event.preventDefault() + this.delegate.formSubmitted(form, submitter) } } }) } + +function submissionDoesNotDismissDialog(form: HTMLFormElement, submitter?: HTMLElement): boolean { + const method = submitter?.getAttribute("formmethod") || form.getAttribute("method") + + return method != "dialog" +} + +function submissionDoesNotTargetIFrame(form: HTMLFormElement, submitter?: HTMLElement): boolean { + const target = submitter?.getAttribute("formtarget") || form.target + + for (const element of document.getElementsByName(target)) { + if (element instanceof HTMLIFrameElement) return false + } + + return true +} diff --git a/src/observers/link_click_observer.ts b/src/observers/link_click_observer.ts index 442f2495e..8e359a2e0 100644 --- a/src/observers/link_click_observer.ts +++ b/src/observers/link_click_observer.ts @@ -36,7 +36,7 @@ export class LinkClickObserver { if (this.clickEventIsSignificant(event)) { const target = (event.composedPath && event.composedPath()[0]) || event.target const link = this.findLinkFromClickTarget(target) - if (link) { + if (link && doesNotTargetIFrame(link)) { const location = this.getLocationForLink(link) if (this.delegate.willFollowLinkToLocation(link, location, event)) { event.preventDefault() @@ -60,7 +60,7 @@ export class LinkClickObserver { findLinkFromClickTarget(target: EventTarget | null) { if (target instanceof Element) { - return target.closest("a[href]:not([target^=_]):not([download])") + return target.closest("a[href]:not([target^=_]):not([download])") } } @@ -68,3 +68,11 @@ export class LinkClickObserver { return expandURL(link.getAttribute("href") || "") } } + +function doesNotTargetIFrame(anchor: HTMLAnchorElement): boolean { + for (const element of document.getElementsByName(anchor.target)) { + if (element instanceof HTMLIFrameElement) return false + } + + return true +} diff --git a/src/tests/fixtures/form.html b/src/tests/fixtures/form.html index bd8081d21..8113b9a58 100644 --- a/src/tests/fixtures/form.html +++ b/src/tests/fixtures/form.html @@ -183,6 +183,7 @@

Form

+
@@ -196,6 +197,15 @@

Form

+ +
+
+ +
+ +
+ +

@@ -316,5 +326,6 @@

Frame: Form

+ diff --git a/src/tests/fixtures/navigation.html b/src/tests/fixtures/navigation.html index 03ae20059..e7e93b93b 100644 --- a/src/tests/fixtures/navigation.html +++ b/src/tests/fixtures/navigation.html @@ -63,8 +63,11 @@

Navigation

Headers link

Delayed link

+

Targets iframe

+ + diff --git a/src/tests/functional/form_submission_tests.ts b/src/tests/functional/form_submission_tests.ts index eabaa2ccd..613fb24a6 100644 --- a/src/tests/functional/form_submission_tests.ts +++ b/src/tests/functional/form_submission_tests.ts @@ -1029,6 +1029,22 @@ test("test POST to external action targetting frame ignored", async ({ page }) = assert.equal(page.url(), "https://httpbin.org/post") }) +test("test form submission skipped with form[target]", async ({ page }) => { + await page.click("#skipped form[target] button") + await nextBeat() + + assert.equal(pathname(page.url()), "/src/tests/fixtures/form.html") + assert.notOk(await formSubmitEnded(page)) +}) + +test("test form submission skipped with submitter button[formtarget]", async ({ page }) => { + await page.click("#skipped [formtarget]") + await nextBeat() + + assert.equal(pathname(page.url()), "/src/tests/fixtures/form.html") + assert.notOk(await formSubmitEnded(page)) +}) + function formSubmitStarted(page: Page) { return getFromLocalStorage(page, "formSubmitStarted") } diff --git a/src/tests/functional/navigation_tests.ts b/src/tests/functional/navigation_tests.ts index 7f4282248..cc39c1a10 100644 --- a/src/tests/functional/navigation_tests.ts +++ b/src/tests/functional/navigation_tests.ts @@ -358,3 +358,10 @@ test("test navigating back whilst a visit is in-flight", async ({ page }) => { assert.equal(pathname(page.url()), "/src/tests/fixtures/navigation.html") assert.equal(await visitAction(page), "restore") }) + +test("test ignores links that target an iframe", async ({ page }) => { + await page.click("#targets-iframe") + await nextBeat() + + assert.equal(pathname(page.url()), "/src/tests/fixtures/navigation.html") +})