-
Notifications
You must be signed in to change notification settings - Fork 15
[Ad-hoc fixes] Ad-hoc fixes autofill logic #780
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
Conversation
d87bc24
to
5c751e7
Compare
29cab10
to
6ea4a46
Compare
6ea4a46
to
e925b63
Compare
c5cfe92
to
c7059af
Compare
af0326f
to
64c7e7f
Compare
package.json
Outdated
"@duckduckgo/content-scope-scripts": "github:duckduckgo/content-scope-scripts#8.1.0", | ||
"@duckduckgo/eslint-config": "github:duckduckgo/eslint-config#v0.1.0", | ||
"@duckduckgo/privacy-test-pages": "github:duckduckgo/privacy-test-pages#1.3.1", | ||
"@duckduckgo/privacy-configuration": "github:duckduckgo/privacy-configuration#dbajpeyi/add-new-autofill-config", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this will need to be changed before merging. Let's make sure we don't forget.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more notes. Hit me up on MM if you want to chat sync.
} | ||
if (this.isHybrid) return false; | ||
|
||
return this.autofillSignal < 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just styling, but when I use the early return pattern, I prefer leaving an empty line after each statement. Especially useful here since we have a conditional with an inline return, otherwise it makes it hard to visually scan the logic. Please do this for all these early returns here. Even the one with the comment, add the whitespace before the comment.
src/config.js
Outdated
let userUnprotectedDomains = null; | ||
let userUnprotectedDomains = []; | ||
/** @type {Record<string, any> | null} */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this space is accidental.
src/Scanner.js
Outdated
* @returns {HTMLFormElement|null} | ||
*/ | ||
get forcedForm() { | ||
return this.device.settings.siteSpecificFeature?.getForcedForm() ?? null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really dislike how we're always forcing to null with the nullish coaleshing operator even when the API naturally returns null, like when using querySelector
. We're doing it over and over. I'm going to flag them all, bear with me. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @returns {HTMLFormElement|null} | ||
*/ | ||
getForcedForm() { | ||
return this.formBoundarySelector ? document.querySelector(this.formBoundarySelector) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What state can this.formBoundarySelector
be? I guess here you're concerned it's null
or undefined
, so you don't need this conditional. You can just return document.querySelector(this.formBoundarySelector)
and that will be null
anyway. https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector#return_value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but tsc is not happy about that :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/site-specific-feature.js
Outdated
* @returns {import('@duckduckgo/privacy-configuration/schema/features/autofill.js').SiteSpecificFixes['formTypeSettings']} | ||
*/ | ||
get formTypeSettings() { | ||
return this.getFeatureSetting('formTypeSettings') ?? []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're very fond of the ??
operator, aren't you? 🙂 TBH, unless it's really needed for specific reasons (i.e. when your value can be 0
or ''
) I prefer the good old ||
. This seems to imply a specific need that it's not there (i.e. as if we were expecting this to be either 0
or ''
which we don't).
src/site-specific-feature.js
Outdated
* @returns {string|null} | ||
*/ | ||
getForcedFormType(form) { | ||
return this.formTypeSettings?.find((config) => form.matches(config.selector))?.type ?? null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you might make a case for null, otherwise this method returns undefined
which is different from the others methods, but still I don't think we care. Let me know if you disagree.
src/Scanner.js
Outdated
/** @type {import("./Form/matching").Matching} matching */ | ||
matching; | ||
|
||
/** @type {boolean} A flag to indicate the forced form has been added */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is somewhat incorrect. The flag will be true even if we tried to find a forced form but failed. Which I think is what you wanted to do and is correct.
I would rename it to avoid confusion, though. Something like hasScannedForForcedForm
. When I looked at the boolean I drafted a whole comment for lines 311-313 to simplify this, but I was wrong so I deleted it. I was misled by the name.
// If the form has only one input and it's unknown, discard the form | ||
if (this.inputs.all.size === 1 && this.inputs.unknown.size === 1) { | ||
this.destroy(); | ||
return; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weren't we doing this somewhere already? Am I misremembering? 🤔
ef70ecf
to
20678cc
Compare
return forcedFormType === 'login'; | ||
} | ||
|
||
if (this.isHybrid) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dbajpeyi You forgot this 😉.
20678cc
to
bc306bf
Compare
src/Scanner.js
Outdated
const forcedForm = this.hasRetrievedForcedForm ? null : this.forcedForm; | ||
this.hasRetrievedForcedForm = true; | ||
const parentForm = forcedForm || form || this.getParentForm(input); | ||
|
||
const parentForm = form || this.getParentForm(input); | ||
if (this.forcedForm && parentForm.contains(this.forcedForm) && this.forcedForm !== parentForm) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to review this again. In the meantime, can you please add a comment above this conditional? Not entirely sure what it's supposed to do 😬.
I think the hasRetrievedForcedForm
part is just confusing me. Maybe I just need to see it without that part, but now I'm fried and can't devote it attention. Will do it on Monday. Please assign the Asana task to me for Monday.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hasRetrievedForcedForm
is making sure we only get forced form for the first input. I have tried to hide that in a function now that does a bit of complex caching, but simplifies the code flow here IMO.
Removed that condition you mentioned, instead preventing child form deletion, if we have a forced form in config now. I think it's equivalent but combines well with existing logic (it's for cases like https://estore.archives.gov/roosevelt/Login.aspx, where nested forms can delete child forms).
src/Scanner.js
Outdated
if (this._forcedForm === null) { | ||
this._forcedForm = this.device.settings.siteSpecificFeature?.getForcedForm() || null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above, for some reason getForcedForm()
is undefined too, so forcing/narrowing it to null here.
60fee7e
to
948f628
Compare
src/Scanner.js
Outdated
if (childForm) { | ||
// unless it's the forced form, in that case we want to keep it. | ||
const forcedFormFromConfig = this.device.settings.siteSpecificFeature?.getForcedForm(); | ||
if (childForm && childForm !== forcedFormFromConfig) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't want to delete the element if we have a forced boundary in the config. E.g in cases where there are nested forms, and one of the child boundaries are forced. In those cases, we want to still keep the forced boundary (added test for it).
948f628
to
2fe6954
Compare
2fe6954
to
6626710
Compare
src/Scanner.js
Outdated
|
||
/** | ||
* Gets the forced form only for the first call, subsequent calls return null | ||
* @returns {HTMLFormElement|HTMLElement|null} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HTMLFormElement inherits from HTMLElement, so using both is not needed here. You should go stricter when possible (not here) but otherwise it's ok to just use the ancestor. I'm pushing the change as I wanted to run tsc
to verify.
* @returns {HTMLFormElement|HTMLElement|null} | |
* @returns {HTMLElement|null} |
Signed-off-by: Emanuele Feliziani <[email protected]>
* Move forcedForm checks in getParentForm Signed-off-by: Emanuele Feliziani <[email protected]> * Fix docs on real-world-html-tests Signed-off-by: Emanuele Feliziani <[email protected]> * Add assets Signed-off-by: Emanuele Feliziani <[email protected]> * Linting fix Signed-off-by: Emanuele Feliziani <[email protected]> --------- Signed-off-by: Emanuele Feliziani <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the latest change merged I think we're good. Thank you for working through the feedback. And remember to point that dependency to main once ready.
We have one approval overseeing the changes while shane is out!
Reviewer: @shakyShane @GioSensation
Asana: https://app.asana.com/0/0/1209507178584801/f
Description
The goal for this PR is to get the core logic of https://app.asana.com/0/72649045549333/1208952994066584/f out, by using the new
C-S-S
ConfigFeature
class. Ideally I want to be able to release this, as by default this setting will be turned off at the moment (native not implemented yet), and autofill's algorithm should take care as usual!processConfig
is updatedConfigFeature
, and implements some utility for the actual featureFor the autofill logic there are two parts:
findEligibleInputs
.The config structure is proposed in https://app.asana.com/0/72649045549333/1209507178584796/f
Steps to test