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

Side by Side Diff: chrome/renderer/autofill/autofill_agent.cc

Issue 10307004: Support datalist UI for <input type=email multiple> (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated Created 8 years, 7 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/renderer/autofill/autofill_agent.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/autofill/autofill_agent.h" 5 #include "chrome/renderer/autofill/autofill_agent.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/time.h" 9 #include "base/time.h"
10 #include "base/string_util.h"
11 #include "base/string_split.h"
10 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
11 #include "chrome/common/autofill_messages.h" 13 #include "chrome/common/autofill_messages.h"
12 #include "chrome/common/chrome_constants.h" 14 #include "chrome/common/chrome_constants.h"
13 #include "chrome/renderer/autofill/form_autofill_util.h" 15 #include "chrome/renderer/autofill/form_autofill_util.h"
14 #include "chrome/renderer/autofill/password_autofill_manager.h" 16 #include "chrome/renderer/autofill/password_autofill_manager.h"
15 #include "content/public/renderer/render_view.h" 17 #include "content/public/renderer/render_view.h"
16 #include "grit/chromium_strings.h" 18 #include "grit/chromium_strings.h"
17 #include "grit/generated_resources.h" 19 #include "grit/generated_resources.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" 20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
(...skipping 16 matching lines...) Expand all
36 using WebKit::WebFormElement; 38 using WebKit::WebFormElement;
37 using WebKit::WebFrame; 39 using WebKit::WebFrame;
38 using WebKit::WebInputElement; 40 using WebKit::WebInputElement;
39 using WebKit::WebKeyboardEvent; 41 using WebKit::WebKeyboardEvent;
40 using WebKit::WebNode; 42 using WebKit::WebNode;
41 using WebKit::WebNodeCollection; 43 using WebKit::WebNodeCollection;
42 using WebKit::WebOptionElement; 44 using WebKit::WebOptionElement;
43 using WebKit::WebString; 45 using WebKit::WebString;
44 using webkit::forms::FormData; 46 using webkit::forms::FormData;
45 using webkit::forms::FormDataPredictions; 47 using webkit::forms::FormDataPredictions;
46 48 #include <iostream>
Ilya Sherman 2012/05/07 23:34:52 nit: Did you mean to add this #include, or was it
keishi 2012/05/09 01:38:21 Sorry my mistake.
47 namespace { 49 namespace {
48 50
49 // The size above which we stop triggering autofill for an input text field 51 // The size above which we stop triggering autofill for an input text field
50 // (so to avoid sending long strings through IPC). 52 // (so to avoid sending long strings through IPC).
51 const size_t kMaximumTextSizeForAutofill = 1000; 53 const size_t kMaximumTextSizeForAutofill = 1000;
52 54
53 void AppendDataListSuggestions(const WebKit::WebInputElement& element, 55 void AppendDataListSuggestions(const WebKit::WebInputElement& element,
54 std::vector<string16>* values, 56 std::vector<string16>* values,
55 std::vector<string16>* labels, 57 std::vector<string16>* labels,
56 std::vector<string16>* icons, 58 std::vector<string16>* icons,
57 std::vector<int>* item_ids) { 59 std::vector<int>* item_ids) {
58 WebNodeCollection options = element.dataListOptions(); 60 WebNodeCollection options = element.dataListOptions();
59 if (options.isNull()) 61 if (options.isNull())
60 return; 62 return;
61 63
64 string16 prefix = element.editingValue();
Ilya Sherman 2012/05/07 23:34:52 What is the difference between element.value() and
keishi 2012/05/09 01:38:21 There is no difference for <input type=text>. But
65 if (element.isMultiple() &&
66 element.formControlType() == WebString::fromUTF8("email")) {
67 std::vector<string16> parts;
68 base::SplitStringDontTrim(prefix, ',', &parts);
69 if (parts.size() > 0)
70 TrimWhitespace(parts[parts.size() - 1], TRIM_LEADING, &prefix);
71 }
62 for (WebOptionElement option = options.firstItem().to<WebOptionElement>(); 72 for (WebOptionElement option = options.firstItem().to<WebOptionElement>();
63 !option.isNull(); option = options.nextItem().to<WebOptionElement>()) { 73 !option.isNull(); option = options.nextItem().to<WebOptionElement>()) {
Ilya Sherman 2012/05/07 23:34:52 nit: This line should be indented one more space.
keishi 2012/05/09 01:38:21 ok.
64 if (!StartsWith(option.value(), element.value(), false)) 74 if (!StartsWith(option.value(), prefix, false))
65 continue; 75 continue;
66 76
67 values->push_back(option.value()); 77 values->push_back(option.value());
68 if (option.value() != option.label()) 78 if (option.value() != option.label())
69 labels->push_back(option.label()); 79 labels->push_back(option.label());
70 else 80 else
71 labels->push_back(string16()); 81 labels->push_back(string16());
72 icons->push_back(string16()); 82 icons->push_back(string16());
73 item_ids->push_back(WebAutofillClient::MenuItemIDDataListEntry); 83 item_ids->push_back(WebAutofillClient::MenuItemIDDataListEntry);
74 } 84 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 case WebAutofillClient::MenuItemIDAutofillOptions: 212 case WebAutofillClient::MenuItemIDAutofillOptions:
203 // User selected 'Autofill Options'. 213 // User selected 'Autofill Options'.
204 Send(new AutofillHostMsg_ShowAutofillDialog(routing_id())); 214 Send(new AutofillHostMsg_ShowAutofillDialog(routing_id()));
205 break; 215 break;
206 case WebAutofillClient::MenuItemIDClearForm: 216 case WebAutofillClient::MenuItemIDClearForm:
207 // User selected 'Clear form'. 217 // User selected 'Clear form'.
208 form_cache_.ClearFormWithElement(element_); 218 form_cache_.ClearFormWithElement(element_);
209 break; 219 break;
210 case WebAutofillClient::MenuItemIDAutocompleteEntry: 220 case WebAutofillClient::MenuItemIDAutocompleteEntry:
211 case WebAutofillClient::MenuItemIDPasswordEntry: 221 case WebAutofillClient::MenuItemIDPasswordEntry:
212 case WebAutofillClient::MenuItemIDDataListEntry: 222 // User selected an Autocomplete or password entry, so we fill directly.
213 // User selected an Autocomplete or password or datalist entry, so we
214 // fill directly.
215 SetNodeText(value, &element_); 223 SetNodeText(value, &element_);
216 break; 224 break;
225 case WebAutofillClient::MenuItemIDDataListEntry: {
226 string16 new_value = value;
227 // If this element takes multiple values then replace the last part with
228 // the suggestion.
229 if (element_.isMultiple() &&
230 element_.formControlType() == WebString::fromUTF8("email")) {
231 std::vector<string16> parts;
232
233 base::SplitStringDontTrim(element_.editingValue(), ',', &parts);
234 if (parts.size() == 0)
235 parts.push_back(string16());
236
237 string16 last_part = parts.back();
238 // We want to keep just the leading whitespace.
239 for (size_t i = 0; i < last_part.size(); ++i) {
240 if (!IsWhitespace(last_part[i])) {
241 last_part = last_part.substr(0, i);
242 break;
243 }
244 }
245 last_part.append(value);
246 parts[parts.size() - 1] = last_part;
247
248 new_value = JoinString(parts, ',');
249 }
250 SetNodeText(new_value, &element_);
251 break;
252 }
217 default: 253 default:
218 // A positive item_id is a unique id for an autofill (vs. autocomplete) 254 // A positive item_id is a unique id for an autofill (vs. autocomplete)
219 // suggestion. 255 // suggestion.
220 DCHECK_GT(item_id, 0); 256 DCHECK_GT(item_id, 0);
221 // Fill the values for the whole form. 257 // Fill the values for the whole form.
222 FillAutofillFormData(node, item_id, AUTOFILL_FILL); 258 FillAutofillFormData(node, item_id, AUTOFILL_FILL);
223 } 259 }
224 } 260 }
225 261
226 void AutofillAgent::didSelectAutofillSuggestion(const WebNode& node, 262 void AutofillAgent::didSelectAutofillSuggestion(const WebNode& node,
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 l.insert(l.end(), labels.begin(), labels.end()); 442 l.insert(l.end(), labels.begin(), labels.end());
407 i.insert(i.end(), icons.begin(), icons.end()); 443 i.insert(i.end(), icons.begin(), icons.end());
408 ids.insert(ids.end(), item_ids.begin(), item_ids.end()); 444 ids.insert(ids.end(), item_ids.begin(), item_ids.end());
409 445
410 WebKit::WebView* web_view = render_view()->GetWebView(); 446 WebKit::WebView* web_view = render_view()->GetWebView();
411 if (!web_view) 447 if (!web_view)
412 return; 448 return;
413 449
414 if (v.empty()) { 450 if (v.empty()) {
415 // No suggestions, any popup currently showing is obsolete. 451 // No suggestions, any popup currently showing is obsolete.
416 web_view->hidePopups(); 452 HidePopups();
417 return; 453 return;
418 } 454 }
419 455
420 // Send to WebKit for display. 456 // Send to WebKit for display.
421 web_view->applyAutofillSuggestions(element, v, l, i, ids); 457 web_view->applyAutofillSuggestions(element, v, l, i, ids);
422 458
423 Send(new AutofillHostMsg_DidShowAutofillSuggestions( 459 Send(new AutofillHostMsg_DidShowAutofillSuggestions(
424 routing_id(), 460 routing_id(),
425 has_autofill_item && !has_shown_autofill_popup_for_current_edit_)); 461 has_autofill_item && !has_shown_autofill_popup_for_current_edit_));
426 has_shown_autofill_popup_for_current_edit_ |= has_autofill_item; 462 has_shown_autofill_popup_for_current_edit_ |= has_autofill_item;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 void AutofillAgent::ShowSuggestions(const WebInputElement& element, 531 void AutofillAgent::ShowSuggestions(const WebInputElement& element,
496 bool autofill_on_empty_values, 532 bool autofill_on_empty_values,
497 bool requires_caret_at_end, 533 bool requires_caret_at_end,
498 bool display_warning_if_disabled) { 534 bool display_warning_if_disabled) {
499 if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() || 535 if (!element.isEnabled() || element.isReadOnly() || !element.isTextField() ||
500 element.isPasswordField() || !element.suggestedValue().isEmpty()) 536 element.isPasswordField() || !element.suggestedValue().isEmpty())
501 return; 537 return;
502 538
503 // Don't attempt to autofill with values that are too large or if filling 539 // Don't attempt to autofill with values that are too large or if filling
504 // criteria are not met. 540 // criteria are not met.
505 WebString value = element.value(); 541 WebString value = element.editingValue();
506 if (value.length() > kMaximumTextSizeForAutofill || 542 if (value.length() > kMaximumTextSizeForAutofill ||
507 (!autofill_on_empty_values && value.isEmpty()) || 543 (!autofill_on_empty_values && value.isEmpty()) ||
508 (requires_caret_at_end && 544 (requires_caret_at_end &&
509 (element.selectionStart() != element.selectionEnd() || 545 (element.selectionStart() != element.selectionEnd() ||
510 element.selectionEnd() != static_cast<int>(value.length())))) { 546 element.selectionEnd() != static_cast<int>(value.length())))) {
511 // Any popup currently showing is obsolete. 547 // Any popup currently showing is obsolete.
512 WebKit::WebView* web_view = render_view()->GetWebView(); 548 HidePopups();
513 if (web_view)
514 web_view->hidePopups();
515 549
516 return; 550 return;
517 } 551 }
518 552
519 element_ = element; 553 element_ = element;
520 554
521 // If autocomplete is disabled at the form level, then we might want to show 555 // If autocomplete is disabled at the form level, then we might want to show
522 // a warning in place of suggestions. However, if autocomplete is disabled 556 // a warning in place of suggestions. However, if autocomplete is disabled
523 // specifically for this field, we never want to show a warning. Otherwise, 557 // specifically for this field, we never want to show a warning. Otherwise,
524 // we might interfere with custom popups (e.g. search suggestions) used by 558 // we might interfere with custom popups (e.g. search suggestions) used by
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 autofill_action_ = action; 613 autofill_action_ = action;
580 Send(new AutofillHostMsg_FillAutofillFormData( 614 Send(new AutofillHostMsg_FillAutofillFormData(
581 routing_id(), autofill_query_id_, form, field, unique_id)); 615 routing_id(), autofill_query_id_, form, field, unique_id));
582 } 616 }
583 617
584 void AutofillAgent::SetNodeText(const string16& value, 618 void AutofillAgent::SetNodeText(const string16& value,
585 WebKit::WebInputElement* node) { 619 WebKit::WebInputElement* node) {
586 string16 substring = value; 620 string16 substring = value;
587 substring = substring.substr(0, node->maxLength()); 621 substring = substring.substr(0, node->maxLength());
588 622
589 node->setValue(substring, true); 623 WebKit::WebView* web_view = render_view()->GetWebView();
624 if (!web_view || !web_view->focusedFrame())
625 return;
626
627 web_view->focusedFrame()->executeCommand(WebString::fromUTF8("selectAll"));
628 web_view->focusedFrame()->executeCommand(WebString::fromUTF8("InsertText"),
629 substring);
Ilya Sherman 2012/05/07 23:34:52 Is there really no more direct way to achieve the
keishi 2012/05/09 01:38:21 There is an inner text field that's being edited b
Ilya Sherman 2012/05/09 02:38:58 If we are exposing |editingValue()|, it makes sens
630 weak_ptr_factory_.InvalidateWeakPtrs();
631 MessageLoop::current()->PostTask(FROM_HERE,
632 base::Bind(&AutofillAgent::HidePopups,
633 weak_ptr_factory_.GetWeakPtr()));
Ilya Sherman 2012/05/07 23:34:52 Hmm, I don't understand the motivation for the cha
keishi 2012/05/09 01:38:21 if you do setValue("a@.com, b@b.com"), the text fi
634 }
635
636 void AutofillAgent::HidePopups() {
637 WebKit::WebView* web_view = render_view()->GetWebView();
638 if (web_view)
639 web_view->hidePopups();
590 } 640 }
591 641
592 } // namespace autofill 642 } // namespace autofill
OLDNEW
« no previous file with comments | « chrome/renderer/autofill/autofill_agent.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698