From 7e76d4f5a84280b21db85d2f17d136796b0e1697 Mon Sep 17 00:00:00 2001 From: Severin Rudie Date: Thu, 21 Nov 2019 14:15:52 -0800 Subject: [PATCH] Fixes 1962: only modify input submit on whitelisted sites --- CHANGELOG.md | 2 +- .../java/org/mozilla/tv/firefox/ext/Js.kt | 64 ++++++++++++++----- .../java/org/mozilla/tv/firefox/ext/String.kt | 13 ++++ .../tv/firefox/webrender/WebRenderFragment.kt | 7 +- 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca84bce4c1..32d85624fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ It diverges in the following ways: ## 4.6 - ? ### Changed - After successful Firefox Account sign in, the page the user was on before sign in is restored (#2805) -- Improved behavior of soft keyboard `submit` button (#1962) +- Improved behavior of soft keyboard `submit` button on whitelisted sites (#1962) ## 4.5 - 2019-09-23 ### Added diff --git a/app/src/main/java/org/mozilla/tv/firefox/ext/Js.kt b/app/src/main/java/org/mozilla/tv/firefox/ext/Js.kt index 558327a4da..1b62a8f0b0 100644 --- a/app/src/main/java/org/mozilla/tv/firefox/ext/Js.kt +++ b/app/src/main/java/org/mozilla/tv/firefox/ext/Js.kt @@ -255,22 +255,54 @@ var _firefoxTV_isPlaybackStateObserverLoaded; * to many user flows (for example, on google.com, people expect a search to kick off after * clicking submit, but it doesn't). This script forces a `submit` call after tab events are * received. + * + * This behavior is added to all elements any time new elements are added to the DOM. */ val ADD_SUBMIT_LISTENER_TO_ALL_INPUTS = """ - |if (typeof MOZ_FFTV_inputListener === 'undefined') { - | MOZ_FFTV_inputListener = (event) => { - | if (event && event.key === 'Tab') { - | // Get the nearest
ancestor - | var formWrapper = Array(...event.path).find((it) => it.tagName === 'FORM') - | if (formWrapper) formWrapper.submit() - | } - | } - |} - | - |Array(...document.getElementsByTagName('input')) - | .forEach((input) => { - | input.removeEventListener("keydown", MOZ_FFTV_inputListener); - | input.addEventListener("keydown", MOZ_FFTV_inputListener); - | }); - """.trimMargin() + (function () { + if (typeof _firefoxTV_inputAddedObserver !== 'undefined') return; + + function inputSubmitListener(event) { + console.log("SEVTEST: keypress detected"); + console.log(event) + if (event && event.key === 'Tab') { + // Get the nearest ancestor + var formWrapper = Array.from(event.path).find((it) => it.tagName === 'FORM') + if (formWrapper) formWrapper.submit() + }; + }; + + function attachListeners() { + console.log("SEVTEST: listeners attached"); + Array.from(document.getElementsByTagName('input')) + .forEach((input) => { + input.removeEventListener("keydown", inputSubmitListener); + input.addEventListener("keydown", inputSubmitListener); + }); + }; + + function nodeContainsInput(node) { + return node.nodeName.toLowerCase() === 'input' || + ((node instanceof Element) && !!node.querySelector('input')); + } + + _firefoxTV_inputAddedObserver = new MutationObserver(mutationList => { + const wasInputAdded = mutationList.some(mutation => { + return mutation.type === 'childList' && + (Array.from(mutation.addedNodes).some(nodeContainsInput)); + }); + + console.log("SEVTEST: mutation. wasInputAdded: " + wasInputAdded); + + if (wasInputAdded) { + /* This may traverse the whole DOM so let's only call it if it's necessary. */ + attachListeners(); + } + }); + + _firefoxTV_inputAddedObserver.observe(document, {subtree: true, childList: true}); + + attachListeners(); + })(); + """.trimIndent() } diff --git a/app/src/main/java/org/mozilla/tv/firefox/ext/String.kt b/app/src/main/java/org/mozilla/tv/firefox/ext/String.kt index 9cc2434aa7..31df33b545 100644 --- a/app/src/main/java/org/mozilla/tv/firefox/ext/String.kt +++ b/app/src/main/java/org/mozilla/tv/firefox/ext/String.kt @@ -88,3 +88,16 @@ val String.isUriYouTubeTvVideo: Boolean val String.isUriFxaSignIn: Boolean get() = this.startsWith("https://accounts.firefox.com/authorization") + +private val addInputScriptWhitelist = setOf( + "https://www.google.", + "http://www.bing.", + "https://www.bing.", + "https://www.amazon.", + "https://www.reddit." +) + +val String.isUrlWhitelistedForSubmitInputHack: Boolean + get() = addInputScriptWhitelist.any { + this.startsWith(it) + } diff --git a/app/src/main/java/org/mozilla/tv/firefox/webrender/WebRenderFragment.kt b/app/src/main/java/org/mozilla/tv/firefox/webrender/WebRenderFragment.kt index aa3ac32b55..dc33c59835 100644 --- a/app/src/main/java/org/mozilla/tv/firefox/webrender/WebRenderFragment.kt +++ b/app/src/main/java/org/mozilla/tv/firefox/webrender/WebRenderFragment.kt @@ -39,6 +39,7 @@ import org.mozilla.tv.firefox.architecture.FirefoxViewModelProviders import org.mozilla.tv.firefox.ext.addSubmitListenerToInputElements import org.mozilla.tv.firefox.ext.couldScrollInDirection import org.mozilla.tv.firefox.ext.focusedDOMElement +import org.mozilla.tv.firefox.ext.isUrlWhitelistedForSubmitInputHack import org.mozilla.tv.firefox.ext.isYoutubeTV import org.mozilla.tv.firefox.ext.maybeGoBackBeforeFxaSignIn import org.mozilla.tv.firefox.ext.observeScrollPosition @@ -123,11 +124,15 @@ class WebRenderFragment : EngineViewLifecycleFragment(), Session.Observer { } override fun onLoadingStateChanged(session: Session, loading: Boolean) { - engineView?.addSubmitListenerToInputElements() if (!loading) { // If the page isn't finished loading, our observers won't be attached to capture the scroll position // and the fix won't work. Unfortunately, I've spent too much time on this so I did not prepare a fix. engineView?.observeScrollPosition() + + if (session.url.isUrlWhitelistedForSubmitInputHack) { + engineView?.addSubmitListenerToInputElements() + } + youtubeBackHandler.onLoadComplete() } }