Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1565)

Unified Diff: chrome/renderer/autofill/autofill_agent.cc

Issue 10024059: DataList UI (Chromium part) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/autofill/autofill_agent.cc
diff --git a/chrome/renderer/autofill/autofill_agent.cc b/chrome/renderer/autofill/autofill_agent.cc
index 294ba19b33f091f1dc731a7d51979b523c3ebd65..971b224a8cc84222dd497c813ea6b55f859250a1 100644
--- a/chrome/renderer/autofill/autofill_agent.cc
+++ b/chrome/renderer/autofill/autofill_agent.cc
@@ -15,13 +15,16 @@
#include "content/public/renderer/render_view.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataListElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeCollection.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebOptionElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/l10n/l10n_util.h"
#include "webkit/forms/form_data.h"
@@ -29,12 +32,15 @@
#include "webkit/forms/form_field.h"
#include "webkit/forms/password_form.h"
+using WebKit::WebDataListElement;
using WebKit::WebFormControlElement;
using WebKit::WebFormElement;
using WebKit::WebFrame;
using WebKit::WebInputElement;
using WebKit::WebKeyboardEvent;
using WebKit::WebNode;
+using WebKit::WebNodeCollection;
+using WebKit::WebOptionElement;
using WebKit::WebString;
using webkit::forms::FormData;
using webkit::forms::FormDataPredictions;
@@ -58,8 +64,6 @@ AutofillAgent::AutofillAgent(
autofill_action_(AUTOFILL_NONE),
display_warning_if_disabled_(false),
was_query_node_autofilled_(false),
- suggestions_clear_index_(-1),
- suggestions_options_index_(-1),
has_shown_autofill_popup_for_current_edit_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
render_view->GetWebView()->setAutofillClient(this);
@@ -146,52 +150,63 @@ bool AutofillAgent::InputElementLostFocus() {
void AutofillAgent::didAcceptAutofillSuggestion(const WebNode& node,
const WebString& value,
const WebString& label,
- int unique_id,
+ int item_id,
unsigned index) {
if (password_autofill_manager_->DidAcceptAutofillSuggestion(node, value))
return;
- DCHECK(node == autofill_query_element_);
-
- if (suggestions_options_index_ != -1 &&
- index == static_cast<unsigned>(suggestions_options_index_)) {
- // User selected 'Autofill Options'.
- Send(new AutofillHostMsg_ShowAutofillDialog(routing_id()));
- } else if (suggestions_clear_index_ != -1 &&
- index == static_cast<unsigned>(suggestions_clear_index_)) {
- // User selected 'Clear form'.
- form_cache_.ClearFormWithElement(autofill_query_element_);
- } else if (!unique_id) {
- // User selected an Autocomplete entry, so we fill directly.
- WebInputElement element = node.toConst<WebInputElement>();
- SetNodeText(value, &element);
- } else {
- // Fill the values for the whole form.
- FillAutofillFormData(node, unique_id, AUTOFILL_FILL);
- }
+ DCHECK(node == element_);
- suggestions_clear_index_ = -1;
- suggestions_options_index_ = -1;
+ switch (item_id) {
+ case WebKit::WarningMessageMenuItemID:
+ case WebKit::SeparatorMenuItemID:
+ NOTREACHED();
+ break;
+ case WebKit::AutofillOptionsMenuItemID:
+ // User selected 'Autofill Options'.
+ Send(new AutofillHostMsg_ShowAutofillDialog(routing_id()));
+ break;
+ case WebKit::ClearFormMenuItemID:
+ // User selected 'Clear form'.
+ form_cache_.ClearFormWithElement(element_);
+ break;
+ case WebKit::AutocompleteEntryMenuItemID:
+ case WebKit::PasswordEntryMenuItemID:
+ case WebKit::DataListEntryMenuItemID:
+ // User selected an Autocomplete or password or datalist entry, so we
+ // fill directly.
+ SetNodeText(value, &element_);
+ break;
+ default:
+ // A positive item_id is a unique id for an autofill (vs. autocomplete)
+ // suggestion.
+ DCHECK_GE(item_id, 0);
Ilya Sherman 2012/04/11 19:09:58 nit: DCHECK_GT
keishi 2012/04/12 14:07:11 Done.
+ // Fill the values for the whole form.
+ FillAutofillFormData(node, item_id, AUTOFILL_FILL);
+ }
}
void AutofillAgent::didSelectAutofillSuggestion(const WebNode& node,
const WebString& value,
const WebString& label,
- int unique_id) {
- DCHECK_GE(unique_id, 0);
+ int item_id) {
if (password_autofill_manager_->DidSelectAutofillSuggestion(node))
return;
didClearAutofillSelection(node);
- FillAutofillFormData(node, unique_id, AUTOFILL_PREVIEW);
+
+ if (item_id <= 0)
+ return;
+
+ FillAutofillFormData(node, item_id, AUTOFILL_PREVIEW);
Ilya Sherman 2012/04/11 19:09:58 nit: Up to you, but I would write lines 198-201 as
keishi 2012/04/12 14:07:11 Done.
}
void AutofillAgent::didClearAutofillSelection(const WebNode& node) {
if (password_autofill_manager_->DidClearAutofillSelection(node))
return;
- if (!autofill_query_element_.isNull() && node == autofill_query_element_) {
- ClearPreviewedFormWithElement(autofill_query_element_,
+ if (!element_.isNull() && node == element_) {
+ ClearPreviewedFormWithElement(element_,
was_query_node_autofilled_);
Ilya Sherman 2012/04/11 19:09:58 nit: No longer a need for line wrapping here?
keishi 2012/04/12 14:07:11 Done.
} else {
// TODO(isherman): There seem to be rare cases where this code *is*
@@ -205,12 +220,6 @@ void AutofillAgent::didClearAutofillSelection(const WebNode& node) {
void AutofillAgent::removeAutocompleteSuggestion(const WebString& name,
const WebString& value) {
- // The index of clear & options will have shifted down.
- if (suggestions_clear_index_ != -1)
- suggestions_clear_index_--;
- if (suggestions_options_index_ != -1)
- suggestions_options_index_--;
-
Send(new AutofillHostMsg_RemoveAutocompleteEntry(routing_id(), name, value));
}
@@ -233,7 +242,7 @@ void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
if (password_autofill_manager_->TextDidChangeInTextField(element)) {
- autofill_query_element_ = element;
+ element_ = element;
return;
}
@@ -250,7 +259,7 @@ void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
const WebKeyboardEvent& event) {
if (password_autofill_manager_->TextFieldHandlingKeyDown(element, event)) {
- autofill_query_element_ = element;
+ element_ = element;
return;
}
@@ -278,16 +287,15 @@ void AutofillAgent::OnSuggestionsReturned(int query_id,
std::vector<string16> l(labels);
std::vector<string16> i(icons);
std::vector<int> ids(unique_ids);
- int separator_index = -1;
DCHECK_GT(ids.size(), 0U);
- if (!autofill_query_element_.isNull() &&
- !autofill_query_element_.autoComplete()) {
+ if (!element_.isNull() &&
+ !element_.autoComplete()) {
Ilya Sherman 2012/04/11 19:09:58 nit: No longer a need for line wrapping here?
keishi 2012/04/12 14:07:11 Done.
// If autofill is disabled and we had suggestions, show a warning instead.
v.assign(1, l10n_util::GetStringUTF16(IDS_AUTOFILL_WARNING_FORM_DISABLED));
l.assign(1, string16());
i.assign(1, string16());
- ids.assign(1, -1);
+ ids.assign(1, WebKit::WarningMessageMenuItemID);
} else if (ids[0] < 0 && ids.size() > 1) {
// If we received a warning instead of suggestions from autofill but regular
// suggestions from autocomplete, don't show the autofill warning.
@@ -311,33 +319,32 @@ void AutofillAgent::OnSuggestionsReturned(int query_id,
}
}
- // The form has been auto-filled, so give the user the chance to clear the
- // form. Append the 'Clear form' menu item.
- if (has_autofill_item &&
- FormWithElementIsAutofilled(autofill_query_element_)) {
- v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
+ if (has_autofill_item) {
+ v.push_back(string16());
l.push_back(string16());
i.push_back(string16());
- ids.push_back(0);
- suggestions_clear_index_ = v.size() - 1;
- separator_index = v.size() - 1;
- }
+ ids.push_back(WebKit::SeparatorMenuItemID);
+
+ // The form has been auto-filled, so give the user the chance to clear the
+ // form. Append the 'Clear form' menu item.
Ilya Sherman 2012/04/11 19:09:58 nit: Please move this comment inside the if-stmt,
keishi 2012/04/12 14:07:11 Done.
+ if (FormWithElementIsAutofilled(element_)) {
+ v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM));
+ l.push_back(string16());
+ i.push_back(string16());
+ ids.push_back(WebKit::ClearFormMenuItemID);
+ }
- if (has_autofill_item) {
// Append the 'Chrome Autofill options' menu item;
v.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_OPTIONS_POPUP));
l.push_back(string16());
i.push_back(string16());
- ids.push_back(0);
- suggestions_options_index_ = v.size() - 1;
- separator_index = values.size();
+ ids.push_back(WebKit::AutofillOptionsMenuItemID);
}
// Send to WebKit for display.
- if (!v.empty() && !autofill_query_element_.isNull() &&
- autofill_query_element_.isFocusable()) {
- web_view->applyAutofillSuggestions(
- autofill_query_element_, v, l, i, ids, separator_index);
+ if (!v.empty() && !element_.isNull() &&
+ element_.isFocusable()) {
Ilya Sherman 2012/04/11 19:09:58 nit: No longer a need for line wrapping here?
keishi 2012/04/12 14:07:11 Done.
+ CombineDataListEntriesAndShow(element_, v, l, i, ids);
}
Send(new AutofillHostMsg_DidShowAutofillSuggestions(
@@ -346,23 +353,76 @@ void AutofillAgent::OnSuggestionsReturned(int query_id,
has_shown_autofill_popup_for_current_edit_ |= has_autofill_item;
}
+void AppendDataListSuggestions(const WebKit::WebInputElement& element,
+ std::vector<string16>* values,
+ std::vector<string16>* labels,
+ std::vector<string16>* icons,
+ std::vector<int>* item_ids) {
+ WebDataListElement dataList = element.dataList();
+ if (dataList.isNull())
+ return;
+
+ WebNodeCollection options = dataList.options();
+ WebOptionElement option = options.firstItem().to<WebOptionElement>();
+ while (!option.isNull()) {
+ values->push_back(option.value());
+ if (option.value() != option.label())
+ labels->push_back(option.label());
+ else
+ labels->push_back(string16());
+ icons->push_back(string16());
+ item_ids->push_back(WebKit::DataListEntryMenuItemID);
+ option = options.nextItem().to<WebOptionElement>();
+ }
+}
Ilya Sherman 2012/04/11 19:09:58 nit: This should be moved into the anonymous names
keishi 2012/04/12 14:07:11 Done.
+
+void AutofillAgent::CombineDataListEntriesAndShow(
+ const WebKit::WebInputElement& element,
+ const std::vector<string16>& values,
+ const std::vector<string16>& labels,
+ const std::vector<string16>& icons,
+ const std::vector<int>& item_ids) {
+ std::vector<string16> v;
+ std::vector<string16> l;
+ std::vector<string16> i;
+ std::vector<int> ids;
+
+ AppendDataListSuggestions(element, &v, &l, &i, &ids);
+
+ // If there are both <datalist> items and Autofill suggestions, add a
+ // separator between them.
+ if (v.size() > 0 && values.size() > 0) {
+ v.push_back(string16());
+ l.push_back(string16());
+ i.push_back(string16());
+ ids.push_back(WebKit::SeparatorMenuItemID);
+ }
+
+ v.insert(v.end(), values.begin(), values.end());
+ l.insert(l.end(), labels.begin(), labels.end());
+ i.insert(i.end(), icons.begin(), icons.end());
+ ids.insert(ids.end(), item_ids.begin(), item_ids.end());
+
+ render_view()->GetWebView()->applyAutofillSuggestions(element, v, l, i, ids);
Ilya Sherman 2012/04/11 19:09:58 Should we call this only if |v| is non-empty?
keishi 2012/04/12 14:07:11 Done.
+}
+
void AutofillAgent::OnFormDataFilled(int query_id,
const webkit::forms::FormData& form) {
if (!render_view()->GetWebView() || query_id != autofill_query_id_)
return;
- was_query_node_autofilled_ = autofill_query_element_.isAutofilled();
+ was_query_node_autofilled_ = element_.isAutofilled();
switch (autofill_action_) {
case AUTOFILL_FILL:
- FillForm(form, autofill_query_element_);
+ FillForm(form, element_);
Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(),
base::TimeTicks::Now()));
break;
case AUTOFILL_PREVIEW:
- didClearAutofillSelection(autofill_query_element_);
+ didClearAutofillSelection(element_);
- PreviewForm(form, autofill_query_element_);
+ PreviewForm(form, element_);
Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
break;
default:
@@ -389,7 +449,7 @@ void AutofillAgent::OnSetAutofillActionFill() {
}
void AutofillAgent::OnClearForm() {
- form_cache_.ClearFormWithElement(autofill_query_element_);
+ form_cache_.ClearFormWithElement(element_);
}
void AutofillAgent::OnSetAutofillActionPreview() {
@@ -397,11 +457,11 @@ void AutofillAgent::OnSetAutofillActionPreview() {
}
void AutofillAgent::OnClearPreviewedForm() {
- didClearAutofillSelection(autofill_query_element_);
+ didClearAutofillSelection(element_);
}
void AutofillAgent::OnSetNodeText(const string16& value) {
- SetNodeText(value, &autofill_query_element_);
+ SetNodeText(value, &element_);
}
void AutofillAgent::OnAcceptPasswordAutofillSuggestion(const string16& value) {
@@ -409,7 +469,7 @@ void AutofillAgent::OnAcceptPasswordAutofillSuggestion(const string16& value) {
// skipped it handling because it believed it would be handled here. If it
// isn't handled here then the browser logic needs to be updated.
bool handled = password_autofill_manager_->DidAcceptAutofillSuggestion(
- autofill_query_element_,
+ element_,
Ilya Sherman 2012/04/11 19:09:58 nit: No longer a need for line wrapping here?
keishi 2012/04/12 14:07:11 Unwrapping "element_," makes it 82 chars.
value);
DCHECK(handled);
}
@@ -418,20 +478,8 @@ void AutofillAgent::ShowSuggestions(const WebInputElement& element,
bool autofill_on_empty_values,
bool requires_caret_at_end,
bool display_warning_if_disabled) {
- // If autocomplete is disabled at the form level, then we might want to show
- // a warning in place of suggestions. However, if autocomplete is disabled
- // specifically for this field, we never want to show a warning. Otherwise,
- // we might interfere with custom popups (e.g. search suggestions) used by
- // the website.
- const WebFormElement form = element.form();
- if (!element.isEnabled() || element.isReadOnly() ||
- (!element.autoComplete() && (form.isNull() || form.autoComplete())) ||
- !element.isTextField() || element.isPasswordField() ||
- !element.suggestedValue().isEmpty())
- return;
-
- // If the field has no name, then we won't have values.
- if (element.nameForAutofill().isEmpty())
+ if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() ||
+ element.isPasswordField() || !element.suggestedValue().isEmpty())
return;
// Don't attempt to autofill with values that are too large or if filling
@@ -450,6 +498,23 @@ void AutofillAgent::ShowSuggestions(const WebInputElement& element,
return;
}
+ element_ = element;
+
+ // If autocomplete is disabled at the form level, then we might want to show
+ // a warning in place of suggestions. However, if autocomplete is disabled
+ // specifically for this field, we never want to show a warning. Otherwise,
+ // we might interfere with custom popups (e.g. search suggestions) used by
+ // the website.
+ const WebFormElement form = element.form();
+ // If the field has no name, then we won't have values.
Ilya Sherman 2012/04/11 19:09:58 nit: I would append this to the end of line 507, a
keishi 2012/04/12 14:07:11 Done.
+ if ((!element.autoComplete() && (form.isNull() || form.autoComplete())) ||
+ element.nameForAutofill().isEmpty()) {
+ CombineDataListEntriesAndShow(element, std::vector<string16>(),
+ std::vector<string16>(),
+ std::vector<string16>(), std::vector<int>());
+ return;
+ }
+
QueryAutofillSuggestions(element, display_warning_if_disabled);
}
@@ -457,7 +522,6 @@ void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
bool display_warning_if_disabled) {
static int query_counter = 0;
autofill_query_id_ = query_counter++;
- autofill_query_element_ = element;
display_warning_if_disabled_ = display_warning_if_disabled;
webkit::forms::FormData form;
@@ -469,7 +533,7 @@ void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
WebFormControlElementToFormField(element, EXTRACT_VALUE, &field);
}
- gfx::Rect bounding_box(autofill_query_element_.boundsInViewportSpace());
+ gfx::Rect bounding_box(element_.boundsInViewportSpace());
Send(new AutofillHostMsg_QueryFormFieldAutofill(routing_id(),
autofill_query_id_,
@@ -482,6 +546,8 @@ void AutofillAgent::QueryAutofillSuggestions(const WebInputElement& element,
void AutofillAgent::FillAutofillFormData(const WebNode& node,
int unique_id,
AutofillAction action) {
+ DCHECK(unique_id > 0);
Ilya Sherman 2012/04/11 19:09:58 nit: DCHECK_GT
keishi 2012/04/12 14:07:11 Done.
+
static int query_counter = 0;
autofill_query_id_ = query_counter++;

Powered by Google App Engine
This is Rietveld 408576698