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
8 changes: 7 additions & 1 deletion src/document-submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ import {
} from './url';
import {Services} from './services';
import {dev, user} from './log';
import {isExtensionScriptInNode} from './element-service';

/**
* @param {!./service/ampdoc-impl.AmpDoc} ampdoc
*/
export function installGlobalSubmitListenerForDoc(ampdoc) {
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.getRootNode().addEventListener(
'submit', onDocumentFormSubmit_, true);
}
}


Expand Down
13 changes: 12 additions & 1 deletion src/element-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,17 @@ export function extensionScriptsInNode(head) {
return scripts;
}

/**
* Verifies that an extension script is present in head for
* 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

*/
export function isExtensionScriptInNode(head, extensionId) {
return extensionScriptsInNode(head).includes(extensionId);
}

/**
* Waits for an extension if its script is present
* @param {!Window} win
Expand All @@ -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.

return Promise.resolve();
}

Expand Down
39 changes: 38 additions & 1 deletion test/functional/test-document-submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import {Services} from '../../src/services';
import {onDocumentFormSubmit_} from '../../src/document-submit';
import {installGlobalSubmitListenerForDoc, onDocumentFormSubmit_} from '../../src/document-submit';

describe('test-document-submit onDocumentFormSubmit_', () => {
let sandbox;
Expand Down Expand Up @@ -46,6 +46,43 @@ describe('test-document-submit onDocumentFormSubmit_', () => {
sandbox.restore();
});

describe('installGlobalSubmitListenerForDoc', () => {
let ampDoc;
let headNode;
let rootNode;
beforeEach(() => {
headNode = document.createElement('head');
rootNode = document.createElement('html');
ampDoc = {
getHeadNode: () => headNode,
getRootNode: () => rootNode,
};
});

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


it('should not register submit listener if amp-form is not registered.',
() => {
const script = document.createElement('script');
script.setAttribute('src', 'https://cdn.ampproject.org/v0/amp-list-0.1.js');
script.setAttribute('custom-element', 'amp-list');
ampDoc.getHeadNode().appendChild(script);
sandbox.spy(rootNode, 'addEventListener');
installGlobalSubmitListenerForDoc(ampDoc);
expect(rootNode.addEventListener).not.to.have.been.called;
});

it('should register submit listener if amp-form extension is registered.',
() => {
const script = document.createElement('script');
script.setAttribute('src', 'https://cdn.ampproject.org/v0/amp-form-0.1.js');
script.setAttribute('custom-element', 'amp-form');
ampDoc.getHeadNode().appendChild(script);
sandbox.spy(rootNode, 'addEventListener');
installGlobalSubmitListenerForDoc(ampDoc);
expect(rootNode.addEventListener).called;
});
});

it('should check target and action attributes', () => {
tgt.removeAttribute('action');
Expand Down
12 changes: 12 additions & 0 deletions test/functional/test-element-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getElementServiceIfAvailable,
getElementServiceIfAvailableForDoc,
getElementServiceIfAvailableForDocInEmbedScope,
isExtensionScriptInNode,
} from '../../src/element-service';
import {
installServiceInEmbedScope,
Expand Down Expand Up @@ -330,6 +331,17 @@ describes.realWin('in single ampdoc', {
expect(service).to.deep.equal({str: 'fake1'});
});
});

it('isExtensionScriptInNode', () => {
const extension = document.createElement('script');
extension.setAttribute('custom-element', 'amp-form');
extension.setAttribute('src', 'https://cdn.ampproject.org/v0/amp-form-0.1.js');
ampdoc.getHeadNode().appendChild(extension);
expect(isExtensionScriptInNode(
ampdoc.getHeadNode(), 'amp-form')).to.equal(true);
expect(isExtensionScriptInNode(
ampdoc.getHeadNode(), 'amp-list')).to.equal(false);
});
});
});

Expand Down