Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install global submit listener only when amp-form extension is registered #17246

Merged
merged 11 commits into from Aug 9, 2018
Merged

Conversation

alabiaga
Copy link
Contributor

@alabiaga alabiaga commented Aug 1, 2018

fixes #16761

  • register global submit event listener only when the amp-form is installed. If amp-form is not present then document-submit will not validate and hijack form submissions allowing the use of native forms.

Next steps is to possibly move some of the logic from document-submit to the amp-form component. I still think this is possible, with some additional code changes and checks in the amp-form extension.

Tested by running the local gulp server and looking at examples/forms.amp.html. I then edited that file and removed the amp-form script and verified that the xhr service (xhr-impl) and this document-submit global event did not intercept any submits from the form via debug statements.

ampdoc.getRootNode().addEventListener('submit', onDocumentFormSubmit_, true);
// Register global submit event listener only if the amp-form
// extension is used. Allowing the usage of native forms, otherwise.
return getElementServiceIfAvailableForDoc(ampdoc, 'amp-form', 'amp-form')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will delay installation of the event listener until amp-form extension is installed. We should instead simply check if the extension will be installed and synchronously install or skip the event listener.

I think we can add a new function to element-service.js that uses extensionScriptsInNode() and rework waitForExtensionIfPresent to use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. Thanks

Copy link

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the PR description with how you tested this change?

* installation.
* @param {HTMLHeadElement|Element|ShadowRoot} head
* @param {string} extensionId
* return {!Promise<boolean>}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@return

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -222,7 +233,7 @@ function waitForExtensionIfPresent(win, extension, head) {

// TODO(jpettitt) investigate registerExtension to short circuit
// the dom call in extensionScriptsInNode()
if (!extensionScriptsInNode(head).includes(extension)) {
if (!isExtensionScriptInNode(head)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should pass extension here right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd assume tests started to fail given this change. Might want to add some tests if not!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right. gulp check-types task did catch this. Thanks all.

};
});

afterEach(() => sandbox.reset());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be necessary if you don't create the sandbox in beforeEach().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

ampdoc.getRootNode().addEventListener('submit', onDocumentFormSubmit_, true);
// Register global submit event listener only if the amp-form
// extension is used. Allowing the usage of native forms, otherwise.
if (isExtensionScriptInNode(ampdoc.getHeadNode(), 'amp-form')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So installGlobalSubmitListenerForDoc get called super early in the AMP runtime (just after styles are installed). I don't know if <head>'s children will be fully parsed by then, meaning we may miss that <script src="amp-form.js"> is included in the head.

That's the reason getElementServiceIfAvailableForDoc waits for whenBodyAvailable first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline yesterday. Modified new isExtensionScriptInNode method to wait for body before making checking that the script is present in head. Thanks

ampdoc.win,
ampdoc.getHeadNode(),
'amp-form')
.then(isAmpFormExtension => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: ampFormInstalled

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @return {!Promise<boolean>}
*/
export function isExtensionScriptInNode(win, head, extensionId) {
return dom.waitForBodyPromise(win.document)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will do the right thing in PWA, since win.document.body != ampdoc.getBody(). 😓

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

sandbox.spy(rootNode, 'addEventListener');
installGlobalSubmitListenerForDoc(ampDoc);
expect(rootNode.addEventListener).called;
installGlobalSubmitListenerForDoc(ampdoc).then(() => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to return the promise in order for Mocha to wait for it. Otherwise, the nested expect() may not be called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@codecov-io
Copy link

codecov-io commented Aug 7, 2018

Codecov Report

Merging #17246 into master will increase coverage by <.01%.
The diff coverage is 100%.

@@            Coverage Diff             @@
##           master   #17246      +/-   ##
==========================================
+ Coverage   77.45%   77.46%   +<.01%     
==========================================
  Files         565      565              
  Lines       41439    41510      +71     
==========================================
+ Hits        32097    32155      +58     
- Misses       9342     9355      +13
Flag Coverage Δ
#integration_tests 35.83% <85.71%> (-0.23%) ⬇️
#unit_tests 76.52% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e0eb99a...eb06a6d. Read the comment docs.

* @return {!Promise<boolean>}
*/
export function isExtensionScriptInNode(
whenbodyAvailPromise, head, extensionId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass in the ampdoc instead of them providing the whenBody and head.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@alabiaga
Copy link
Contributor Author

alabiaga commented Aug 7, 2018

@choumx @jridgewell note the comment in test-document-submit.js. I tried fixing the test but was not able too and was spending too much time figuring out why my fix wasn't working so i left a comment in the meantime. I'll have to revisit. Let me know if I can follow up in a separate PR or if i should just fix it. Thanks

Copy link

@dreamofabear dreamofabear left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alabiaga Fixed the recursive test issue. Previously, the global submit listener installed in _init_tests.js was picking up the submit event. With your change, it was no longer adding the event listener since the amp-form script is not present in the document head.

To fix it, we needed to add the amp-form script to the test window's document head and install the global submit listener given the correct AmpDoc.

@alabiaga
Copy link
Contributor Author

alabiaga commented Aug 9, 2018

@choumx thanks for the fix. As discussed offline I actually did this very same change and yet it wasn't passing for me.

@alabiaga alabiaga merged commit a935150 into ampproject:master Aug 9, 2018
@alabiaga
Copy link
Contributor Author

alabiaga commented Aug 9, 2018

@choumx oh i see you installed the global submit event listener in the beforeEach which I didn't do. Thanks again

@alabiaga alabiaga deleted the 16761 branch August 9, 2018 02:01
kevinkassimo pushed a commit to kevinkassimo/amphtml that referenced this pull request Aug 9, 2018
…ered (ampproject#17246)

* install global submit listener only when amp-form extension is registered

* fix tests

* address comments

* fixes

* wait for body before checking for script in head

* fix test

* add comment

* address comments

* Fix form recursive submit test.

* Remove comment.
Enriqe pushed a commit to Enriqe/amphtml that referenced this pull request Nov 28, 2018
…ered (ampproject#17246)

* install global submit listener only when amp-form extension is registered

* fix tests

* address comments

* fixes

* wait for body before checking for script in head

* fix test

* add comment

* address comments

* Fix form recursive submit test.

* Remove comment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix <form> elements in invalid AMP contexts
6 participants