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

Exposing input change event and form.submit action #5707

Merged
merged 6 commits into from Oct 27, 2016

Conversation

mkhatib
Copy link
Contributor

@mkhatib mkhatib commented Oct 20, 2016

Implements #4272

Play with the demo at the bottom of the page here. Make sure to toggle both amp-form and form-submit experiments.

@@ -138,6 +135,14 @@ export class AmpForm {
/** @const @private {!./form-validators.FormValidator} */
this.validator_ = getFormValidator(this.form_);

this.actions_.installActionHandler(this.form_, invocation => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dvoytenko is this the right thing to do here? Or using addGlobalMethodHandler a better option?

Copy link
Contributor

Choose a reason for hiding this comment

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

Something like installActionHandler is definitely better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ack

// TODO: ASK @dima about this? Is this limited to AMP-elements for security
// reasons? If yes, shouldn't one check the tagname rather than the id?
//user().assert(target.id && target.id.substring(0, 4) == 'amp-',
// 'AMP element is expected: %s', debugid);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dvoytenko why is this limited to AMP elements? Would it be ok to relax this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah. Probably would be ok to relax. The intention here is really to reduce a probability of error by installing this handler on an accidental element. But I just checked and it looks like installActionHandler is already a restricted API in presubmits. So we don't need to worry too much about misuse.

A slightly bigger problem is on the trigger side - where you also disabled AMP check. The issue is that if a publisher accidentally specifies the wrong target, they'll never know - a very easy mistake to make. So, I think, we still need some form of whitelist.

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

// TODO: ASK @dima about this? Is this limited to AMP-elements for security
// reasons? If yes, shouldn't one check the tagname rather than the id?
//user().assert(target.id && target.id.substring(0, 4) == 'amp-',
// 'AMP element is expected: %s', debugid);
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah. Probably would be ok to relax. The intention here is really to reduce a probability of error by installing this handler on an accidental element. But I just checked and it looks like installActionHandler is already a restricted API in presubmits. So we don't need to worry too much about misuse.

A slightly bigger problem is on the trigger side - where you also disabled AMP check. The issue is that if a publisher accidentally specifies the wrong target, they'll never know - a very easy mistake to make. So, I think, we still need some form of whitelist.

@@ -138,6 +135,14 @@ export class AmpForm {
/** @const @private {!./form-validators.FormValidator} */
this.validator_ = getFormValidator(this.form_);

this.actions_.installActionHandler(this.form_, invocation => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Something like installActionHandler is definitely better.

@@ -163,20 +173,24 @@ export class AmpForm {
* invalid. stopImmediatePropagation allows us to make sure we don't trigger it
*
*
* @param {!Event} e
* @param {?Event} optEvent
Copy link
Contributor

Choose a reason for hiding this comment

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

opt_event

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

@mkhatib
Copy link
Contributor Author

mkhatib commented Oct 25, 2016

@dvoytenko added the whitelist, PTAL 👀 - will be adding tests in the next commit

Copy link
Contributor

@dvoytenko dvoytenko left a comment

Choose a reason for hiding this comment

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

Looks great. Couple of requests and looking forward to tests.

@@ -152,6 +157,11 @@ export class AmpForm {
onInputInteraction_(e);
this.validator_.onInput(e);
});
this.form_.addEventListener('change', e => {
const input = e.target;
// TODO(#5702): Consider a debounced-input event for text-type inputs.
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO(ldap, #issue)

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

@@ -271,9 +273,17 @@ export class ActionService {
return;
}

// Check if this is an element has a known action.
const supportedActions = ELEMENTS_ACTIONS_MAP_[lowerTagName];
if (target[ACTION_QUEUE_] && supportedActions &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you not initializing ACTION_QUEUE_ right here? Are risk conditions do not apply here? Is it even worth the cost?

Btw, this if and the previous one (target.id ~= amp-) can be combined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem with initializing ACTION_QUEUE_ here is basically initialize it to what? An empty array? This case specifically will probably be reached if the element uses installActionHandler method to initialize the ACTION_QUEUE_ to be an object with a fake push method to allow executing the handler passed.

So wouldn't initializing it here basically fail silently for these cases? We could throw a better error when not initialized - basically user().error('Action queue not initialized, probably tried to execute before calling installActionHandler on %s', this.element) - or something like that. No?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not quite. We indeed initialize to an empty array. You can see it just 5 lines above for an amp- case (I mentioned that this should probably be the same code). What this gives you is that it buffers up actions in an array until installActionHandler is called. As you can see here, when installActionHandler is called, it goes over buffered actions and sends them to the handler. This way we remove risk condition between when a user can activate an action and when installActionHandler is called. That makes sense since installActionHandler installation depends on asynchronous script download.

In cases like this it's possible that it's "too late" to execute an action. If this happens, we can add "deferred" flag to an action that's not executed immediately. We do this here, but to my knowledge no actions use it yet. So we can punt on this here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Make sense! Thanks for explaining. I'll update the code.

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.

@@ -163,9 +167,6 @@ export class ActionService {
*/
installActionHandler(target, handler) {
const debugid = target.tagName + '#' + target.id;
user().assert(target.id && target.id.substring(0, 4) == 'amp-',
Copy link
Contributor

Choose a reason for hiding this comment

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

(1) This should be a dev().assert()
(2) Why not also check here supportedActions? This way you get an early notification as a developer that an element (at least) must be whitelisted.

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

@@ -33,6 +33,10 @@ const ACTION_QUEUE_ = '__AMP_ACTION_QUEUE__';
/** @const {string} */
const DEFAULT_METHOD_ = 'activate';

/** @const {!Object<string,!Array<string>>} */
const ELEMENTS_ACTIONS_MAP_ = {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is good for now, but just FYI: it'd be even enough to just check for element name - the most likely error is confusing element's for another. If this set goes out of control - we can simply move the assertion for "unknown action" into the form's action handler itself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ack

@mkhatib mkhatib changed the title WIP: Exposing input change event and form.submit action Exposing input change event and form.submit action Oct 26, 2016
@mkhatib
Copy link
Contributor Author

mkhatib commented Oct 26, 2016

@dvoytenko added tests and addressed comments PTAL 👀

this.handleSubmit_();
}
}

/** @private */
installSubmitHandler_() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we rename this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes 😄 I thought I did. Will do

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

@dvoytenko
Copy link
Contributor

LGTM

@mkhatib mkhatib merged commit 62ca0b6 into ampproject:master Oct 27, 2016
@mkhatib mkhatib deleted the input-change-submit branch October 27, 2016 22:05
Lith pushed a commit to Lith/amphtml that referenced this pull request Dec 22, 2016
Lith pushed a commit to Lith/amphtml that referenced this pull request Dec 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants