From 6d39ceb7fe9cf13a3494ac1ed44e85b942237423 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Fri, 30 Dec 2022 11:41:45 -0500 Subject: [PATCH] Close Issue #834 Closes [hotwired/turbo#834][] When applications embed [Google Adsense][]-powered `` elements, the snippets they provide render them **with** a `[name]` attribute that's set to the empty string `""`: ```html ``` Note the `[name=""]` in the snippet. The guard clauses in the `FormSubmitObserver` and `LinkClickObserver` classes that prevent Turbo Drive from interfering with `` clicks and `` submissions that target `` elements do not account for the presence of an ``. This commit extends those guard clauses to first check for the presence of `a[target]`, `form[target]`, and `input[formtarget]` or `button[formtarget]` attributes before searching the document for an `iframe[name]` that matches. Additionally, it adds tests to cover a special-case scenario where there **is** an `iframe[name=""]` **and** an element that targets it (for example, `a[target=""]`). For example, consider the following example (along with a Turbo-less [JSFiddle][] that reproduces the behavior): ```html Targets [name=""] ``` When clicked, the `` element drives the entire page. In our test suite, there are test cases that cover this behavior, and ensure that Turbo doesn't interfere in these scenarios. [Google Adsense]: https://www.google.com/adsense/start/ [hotwired/turbo#834]: https://github.com/hotwired/turbo/issues/834 [JSFiddle]: https://jsfiddle.net/hk6587oz/ --- src/observers/form_submit_observer.ts | 14 ++++--- src/observers/link_click_observer.ts | 12 ++++-- src/tests/fixtures/navigation.html | 24 ++++++++++- src/tests/functional/navigation_tests.ts | 53 +++++++++++++++++++++++- src/tests/helpers/page.ts | 11 +++++ 5 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/observers/form_submit_observer.ts b/src/observers/form_submit_observer.ts index 1ef4ca33d..3700d0726 100644 --- a/src/observers/form_submit_observer.ts +++ b/src/observers/form_submit_observer.ts @@ -58,11 +58,15 @@ function submissionDoesNotDismissDialog(form: HTMLFormElement, submitter?: HTMLE } function submissionDoesNotTargetIFrame(form: HTMLFormElement, submitter?: HTMLElement): boolean { - const target = submitter?.getAttribute("formtarget") || form.target + if (submitter?.hasAttribute("formtarget") || form.hasAttribute("target")) { + const target = submitter?.getAttribute("formtarget") || form.target - for (const element of document.getElementsByName(target)) { - if (element instanceof HTMLIFrameElement) return false - } + for (const element of document.getElementsByName(target)) { + if (element instanceof HTMLIFrameElement) return false + } - return true + return true + } else { + return true + } } diff --git a/src/observers/link_click_observer.ts b/src/observers/link_click_observer.ts index 6b587c3a5..b5d7c442f 100644 --- a/src/observers/link_click_observer.ts +++ b/src/observers/link_click_observer.ts @@ -71,9 +71,13 @@ export class LinkClickObserver { } function doesNotTargetIFrame(anchor: HTMLAnchorElement): boolean { - for (const element of document.getElementsByName(anchor.target)) { - if (element instanceof HTMLIFrameElement) return false - } + if (anchor.hasAttribute("target")) { + for (const element of document.getElementsByName(anchor.target)) { + if (element instanceof HTMLIFrameElement) return false + } - return true + return true + } else { + return true + } } diff --git a/src/tests/fixtures/navigation.html b/src/tests/fixtures/navigation.html index c78c47d9f..aed08b492 100644 --- a/src/tests/fixtures/navigation.html +++ b/src/tests/fixtures/navigation.html @@ -79,12 +79,34 @@ Navigation
Delayed link
Targets iframe
Targets iframe[name="iframe"]
Targets iframe[name=""]
+
Redirect to cache_observer.html