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
15 changes: 11 additions & 4 deletions src/document-submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,21 @@ import {isExtensionScriptInNode} from './element-service';

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

if (isAmpFormExtension) {
ampdoc.getRootNode().addEventListener(
'submit', onDocumentFormSubmit_, true);
}
});
}


Expand Down
21 changes: 18 additions & 3 deletions src/element-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,29 @@ export function extensionScriptsInNode(head) {
return scripts;
}

/**
* Waits for body to be present then verifies that an extension script is
* present in head for installation.
* @param {!Window} win
* @param {HTMLHeadElement|Element|ShadowRoot} head
* @param {string} extensionId
* @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

.then(() => {
return extensionScriptInNode(head, extensionId);
});
}

/**
* Verifies that an extension script is present in head for
* installation.
* @param {HTMLHeadElement|Element|ShadowRoot} head
* @param {string} extensionId
* @return {boolean}
* @private
*/
export function isExtensionScriptInNode(head, extensionId) {
function extensionScriptInNode(head, extensionId) {
return extensionScriptsInNode(head).includes(extensionId);
}

Expand All @@ -233,7 +248,7 @@ function waitForExtensionIfPresent(win, extension, head) {

// TODO(jpettitt) investigate registerExtension to short circuit
// the dom call in extensionScriptsInNode()
if (!isExtensionScriptInNode(head, extension)) {
if (!extensionScriptInNode(head, extension)) {
return Promise.resolve();
}

Expand Down
36 changes: 22 additions & 14 deletions test/functional/test-document-submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,38 +47,46 @@ describe('test-document-submit onDocumentFormSubmit_', () => {
});

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

/**
* @param {string} extension
*/
const createScript = extension => {
const script = document.createElement('script');
script.setAttribute('src',
'https://cdn.ampproject.org/v0/' + extension + '-0.1.js');
script.setAttribute('custom-element', extension);
return script;
};

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);
ampdoc.getHeadNode().appendChild(createScript('amp-list'));
sandbox.spy(rootNode, 'addEventListener');
installGlobalSubmitListenerForDoc(ampDoc);
expect(rootNode.addEventListener).not.to.have.been.called;
installGlobalSubmitListenerForDoc(ampdoc).then(() => {
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);
ampdoc.getHeadNode().appendChild(createScript('amp-form'));
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

expect(rootNode.addEventListener).called;
});
});
});

Expand Down
10 changes: 6 additions & 4 deletions test/functional/test-element-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,12 @@ describes.realWin('in single ampdoc', {
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);
return isExtensionScriptInNode(
ampdoc.win,
ampdoc.getHeadNode(),
'amp-form').then(isAmpForminNode => {
expect(isAmpForminNode).to.equal(true);
});
});
});
});
Expand Down