Commit ec35d9cb authored by Moe Ahmadi's avatar Moe Ahmadi Committed by Commit Bot

[AF][IOS] Only clear fields in the same section as the one initiating clear

Bug: 816941
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I5fae03657bd3e05ed101b4b85c2904aa28b3611d
Reviewed-on: https://chromium-review.googlesource.com/1089857Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Reviewed-by: default avatarJohn Wu <jzw@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Commit-Queue: Moe Ahmadi <mahmadi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#565705}
parent d8e41f7a
......@@ -478,8 +478,9 @@ void GetFormAndField(autofill::FormData* form,
value:base::SysNSStringToUTF16(suggestion.value)];
} else if (suggestion.identifier == autofill::POPUP_ITEM_ID_CLEAR_FORM) {
[jsAutofillManager_
clearAutofilledFieldsForFormNamed:formName
completionHandler:suggestionHandledCompletion_];
clearAutofilledFieldsForFormName:formName
fieldIdentifier:fieldIdentifier
completionHandler:suggestionHandledCompletion_];
suggestionHandledCompletion_ = nil;
} else {
NOTREACHED() << "unknown identifier " << suggestion.identifier;
......@@ -735,7 +736,10 @@ void GetFormAndField(autofill::FormData* form,
if (field.value.empty() || !field.is_autofilled)
continue;
fieldsData.SetKey(base::UTF16ToUTF8(field.id), base::Value(field.value));
base::Value fieldData(base::Value::Type::DICTIONARY);
fieldData.SetKey("value", base::Value(field.value));
fieldData.SetKey("section", base::Value(field.section));
fieldsData.SetKey(base::UTF16ToUTF8(field.id), std::move(fieldData));
}
autofillData.SetKey("fields", std::move(fieldsData));
......
......@@ -13,9 +13,13 @@
@interface FakeJSAutofillManager : JsAutofillManager
// The name of the form that was most recently passed to
// |clearAutofilledFieldsForFormNamed:completionHandler:|.
// |clearAutofilledFieldsForFormName:fieldIdentifier:completionHandler:|.
@property(nonatomic, copy, readonly) NSString* lastClearedFormName;
// The field identifier that was most recently passed to
// |clearAutofilledFieldsForFormName:fieldIdentifier:completionHandler:|.
@property(nonatomic, copy, readonly) NSString* lastClearedFieldIdentifier;
@end
#endif // COMPONENTS_AUTOFILL_IOS_BROWSER_FAKE_JS_AUTOFILL_MANAGER_H_
......@@ -14,11 +14,15 @@
@implementation FakeJSAutofillManager
@synthesize lastClearedFormName = _lastClearedFormName;
@synthesize lastClearedFieldIdentifier = _lastClearedFieldIdentifier;
- (void)clearAutofilledFieldsForFormNamed:(NSString*)formName
completionHandler:(ProceduralBlock)completionHandler {
- (void)clearAutofilledFieldsForFormName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
completionHandler:(ProceduralBlock)completionHandler {
web::WebThread::PostTask(web::WebThread::UI, FROM_HERE, base::BindOnce(^{
_lastClearedFormName = [formName copy];
_lastClearedFieldIdentifier =
[fieldIdentifier copy];
completionHandler();
}));
}
......
......@@ -41,10 +41,12 @@
// autofilled are not modified. Field contents are cleared, and Autofill flag
// and styling are removed. 'change' events are sent for fields whose contents
// changed.
// |fieldIdentifier| identifies the field that initiated the clear action.
// |completionHandler| is called after the forms are filled. |completionHandler|
// cannot be nil.
- (void)clearAutofilledFieldsForFormNamed:(NSString*)formName
completionHandler:(ProceduralBlock)completionHandler;
- (void)clearAutofilledFieldsForFormName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
completionHandler:(ProceduralBlock)completionHandler;
// Marks up the form with autofill field prediction data (diagnostic tool).
- (void)fillPredictionData:(NSString*)dataString;
......
......@@ -109,13 +109,18 @@
}];
}
- (void)clearAutofilledFieldsForFormNamed:(NSString*)formName
completionHandler:(ProceduralBlock)completionHandler {
- (void)clearAutofilledFieldsForFormName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
completionHandler:(ProceduralBlock)completionHandler {
DCHECK(completionHandler);
NSString* script =
[NSString stringWithFormat:
@"__gCrWeb.autofill.clearAutofilledFields(%s);",
base::GetQuotedJSONString([formName UTF8String]).c_str()];
NSString* script = [NSString
stringWithFormat:@"__gCrWeb.autofill.clearAutofilledFields(%s, %s);",
base::GetQuotedJSONString(
base::SysNSStringToUTF8(formName))
.c_str(),
base::GetQuotedJSONString(
base::SysNSStringToUTF8(fieldIdentifier))
.c_str()];
[_receiver executeJavaScript:script
completionHandler:^(id, NSError*) {
completionHandler();
......
......@@ -21,7 +21,7 @@ goog.provide('__crWeb.autofill');
* The autofill data for a form.
* @typedef {{
* formName: string,
* fields: !Object<string, string>,
* fields: !Object<string, !Object<string, string>>,
* }}
*/
var FormData;
......@@ -279,10 +279,10 @@ __gCrWeb.autofill['fillForm'] = function(data, forceFillFieldIdentifier) {
if (__gCrWeb.fill.isCheckableElement(element))
continue;
// Skip fields if autofill data is missing.
// Skip fields for which autofill data is missing.
var fieldIdentifier = __gCrWeb.form.getFieldIdentifier(element);
var value = data.fields[fieldIdentifier];
if (!value)
var fieldData = data.fields[fieldIdentifier];
if (!fieldData)
continue;
// Skip non-empty fields unless:
......@@ -302,15 +302,16 @@ __gCrWeb.autofill['fillForm'] = function(data, forceFillFieldIdentifier) {
continue;
}
(function(_element, _value, _delay) {
(function(_element, _value, _section, _delay) {
window.setTimeout(function() {
__gCrWeb.fill.setInputElementValue(_value, _element, function() {
_element.setAttribute('chrome-autofilled', '');
_element.isAutofilled = true;
_element.autofillSection = _section;
_element.addEventListener('input', controlElementInputListener_);
});
}, _delay);
})(element, value, delay);
})(element, fieldData.value, fieldData.section, delay);
}
if (form) {
......@@ -329,30 +330,45 @@ __gCrWeb.autofill['fillForm'] = function(data, forceFillFieldIdentifier) {
}
};
// TODO(crbug.com/816941): Clear should only clear the current section and not
// the whole form.
/**
* Clear autofilled fields of the specified form section. Fields that are not
* currently autofilled are not modified.
* currently autofilled or do not belong to the same section as that of the
* field with |fieldIdentifier| are not modified. If the field identified by
* |fieldIdentifier| cannot be found all autofilled form fields get cleared.
* Field contents are cleared, and Autofill flag and styling are removed.
* 'change' events are sent for fields whose contents changed.
* Based on FormCache::ClearSectionWithElement().
*
* @param {string} formName Identifier for form element (from
* getFormIdentifier).
* @param {string} fieldIdentifier Identifier for form field initiating the
* clear action.
*/
__gCrWeb.autofill['clearAutofilledFields'] = function(formName) {
__gCrWeb.autofill['clearAutofilledFields'] = function(
formName, fieldIdentifier) {
var form = __gCrWeb.form.getFormElementFromIdentifier(formName);
var controlElements = form ?
__gCrWeb.form.getFormControlElements(form) :
getUnownedAutofillableFormFieldElements_(document.all, /*fieldsets=*/[]);
var formField = null;
for (var i = 0; i < controlElements.length; ++i) {
if (__gCrWeb.form.getFieldIdentifier(controlElements[i]) ==
fieldIdentifier) {
formField = controlElements[i];
break;
}
}
for (var i = 0, delay = 0; i < controlElements.length;
++i, delay += __gCrWeb.autofill.delayBetweenFieldFillingMs) {
var element = controlElements[i];
if (!element.isAutofilled || element.disabled)
continue;
if (formField && formField.autofillSection != element.autofillSection)
continue;
var value = null;
if (__gCrWeb.fill.isTextInput(element) ||
__gCrWeb.fill.isTextAreaElement(element)) {
......
......@@ -120,13 +120,15 @@
#pragma mark - Public Methods
- (void)clearFormWithName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
completionHandler:(nullable void (^)(void))completionHandler {
[_JSAutofillManager clearAutofilledFieldsForFormNamed:formName
completionHandler:^{
if (completionHandler) {
completionHandler();
}
}];
[_JSAutofillManager clearAutofilledFieldsForFormName:formName
fieldIdentifier:fieldIdentifier
completionHandler:^{
if (completionHandler) {
completionHandler();
}
}];
}
- (void)fetchSuggestionsForFormWithName:(NSString*)formName
......
......@@ -143,6 +143,7 @@ TEST_F(CWVAutofillControllerTest, FillSuggestion) {
TEST_F(CWVAutofillControllerTest, ClearForm) {
__block BOOL clear_form_completion_was_called = NO;
[autofill_controller_ clearFormWithName:kTestFormName
fieldIdentifier:kTestFieldIdentifier
completionHandler:^{
clear_form_completion_was_called = YES;
}];
......@@ -152,6 +153,8 @@ TEST_F(CWVAutofillControllerTest, ClearForm) {
return clear_form_completion_was_called;
}));
EXPECT_NSEQ(kTestFormName, js_autofill_manager_.lastClearedFormName);
EXPECT_NSEQ(kTestFieldIdentifier,
js_autofill_manager_.lastClearedFieldIdentifier);
}
// Tests CWVAutofillController focus previous field.
......
......@@ -24,15 +24,22 @@ CWV_EXPORT
- (instancetype)init NS_UNAVAILABLE;
// Clears the html form element with the 'name' attribute equal to |formName|.
// No-op if no such form is found.
// Clears the fields that belong to the same autofill section as the field
// identified by |fieldIdentifier| in the form named |formName|.
// No-op if no such form can be found in the current page. If the field
// identified by |fieldIdentifier| cannot be found the entire form gets cleared.
// |fieldIdentifier| identifies the field that had focus. It is passed to
// CWVAutofillControllerDelegate and forwarded to this method.
// |completionHandler| will only be called on success.
- (void)clearFormWithName:(NSString*)formName
fieldIdentifier:(NSString*)fieldIdentifier
completionHandler:(nullable void (^)(void))completionHandler;
// For the field named |fieldName|, identified by |fieldIdentifier| in the form
// named |formName|, fetches suggestions that can be used to autofill.
// No-op if no such form and field can be found in the current page.
// |fieldIdentifier| identifies the field that had focus. It is passed to
// CWVAutofillControllerDelegate and forwarded to this method.
// |completionHandler| will only be called on success.
- (void)fetchSuggestionsForFormWithName:(NSString*)formName
fieldName:(NSString*)fieldName
......
......@@ -64,13 +64,14 @@
for (CWVAutofillSuggestion* suggestion in suggestions) {
[alertController addAction:[self actionForSuggestion:suggestion]];
}
UIAlertAction* clearAction =
[UIAlertAction actionWithTitle:@"Clear"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* _Nonnull action) {
[autofillController clearFormWithName:formName
completionHandler:nil];
}];
UIAlertAction* clearAction = [UIAlertAction
actionWithTitle:@"Clear"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* _Nonnull action) {
[autofillController clearFormWithName:formName
fieldIdentifier:fieldIdentifier
completionHandler:nil];
}];
[alertController addAction:clearAction];
[strongSelf presentAlertController:alertController];
......
......@@ -199,7 +199,9 @@ TEST_F(WebViewAutofillTest, TestSuggestionFetchFillClear) {
return [fetched_suggestion.value isEqualToString:filled_value];
}));
ASSERT_NSEQ(nil, filled_error);
[autofill_controller_ clearFormWithName:kTestFormName completionHandler:nil];
[autofill_controller_ clearFormWithName:kTestFormName
fieldIdentifier:kTestFieldID
completionHandler:nil];
NSString* cleared_script = [NSString
stringWithFormat:@"document.getElementById('%@').value", kTestFieldID];
__block NSError* cleared_error = nil;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment