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

Side by Side Diff: chrome/renderer/form_manager.cc

Issue 6033010: Support autocompletion for HTMl5 tags:"email", "month" and "tel". (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix format errors and change to use toWebInputElement(). Created 9 years, 11 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/form_manager.h" 5 #include "chrome/renderer/form_manager.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/scoped_vector.h" 8 #include "base/scoped_vector.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "base/stl_util-inl.h" 10 #include "base/stl_util-inl.h"
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 // For select-one elements copy option strings. 266 // For select-one elements copy option strings.
267 WebVector<WebElement> list_items = select_element.listItems(); 267 WebVector<WebElement> list_items = select_element.listItems();
268 option_strings->reserve(list_items.size()); 268 option_strings->reserve(list_items.size());
269 for (size_t i = 0; i < list_items.size(); ++i) { 269 for (size_t i = 0; i < list_items.size(); ++i) {
270 if (list_items[i].hasTagName("option")) 270 if (list_items[i].hasTagName("option"))
271 option_strings->push_back(list_items[i].to<WebOptionElement>().value()); 271 option_strings->push_back(list_items[i].to<WebOptionElement>().value());
272 } 272 }
273 } 273 }
274 } 274 }
275 275
276 // In HTML5, all text fields except password are text input fields to
277 // autocomplete.
278 static bool IsTextInput(const WebInputElement* element) {
279 if (!element)
280 return false;
281
282 return element->isTextField() && !element->isPasswordField();
283 }
284
276 } // namespace 285 } // namespace
277 286
278 struct FormManager::FormElement { 287 struct FormManager::FormElement {
279 WebKit::WebFormElement form_element; 288 WebKit::WebFormElement form_element;
280 std::vector<WebKit::WebFormControlElement> control_elements; 289 std::vector<WebKit::WebFormControlElement> control_elements;
281 std::vector<string16> control_values; 290 std::vector<string16> control_values;
282 }; 291 };
283 292
284 FormManager::FormManager() { 293 FormManager::FormManager() {
285 } 294 }
(...skipping 15 matching lines...) Expand all
301 field->set_name(element.nameForAutofill()); 310 field->set_name(element.nameForAutofill());
302 field->set_form_control_type(element.formControlType()); 311 field->set_form_control_type(element.formControlType());
303 312
304 if (extract_mask & EXTRACT_OPTIONS) { 313 if (extract_mask & EXTRACT_OPTIONS) {
305 // Set option strings on the field if available. 314 // Set option strings on the field if available.
306 std::vector<string16> option_strings; 315 std::vector<string16> option_strings;
307 GetOptionStringsFromElement(element, &option_strings); 316 GetOptionStringsFromElement(element, &option_strings);
308 field->set_option_strings(option_strings); 317 field->set_option_strings(option_strings);
309 } 318 }
310 319
311 if (element.formControlType() == WebString::fromUTF8("text")) { 320 const WebInputElement* input_element =
312 const WebInputElement& input_element = element.toConst<WebInputElement>(); 321 WebInputElement::toWebInputElement(&element);
313 field->set_max_length(input_element.maxLength()); 322 if (IsTextInput(input_element)) {
314 field->set_autofilled(input_element.isAutofilled()); 323 field->set_max_length(input_element->maxLength());
324 field->set_autofilled(input_element->isAutofilled());
315 } 325 }
316 326
317 if (!(extract_mask & EXTRACT_VALUE)) 327 if (!(extract_mask & EXTRACT_VALUE))
318 return; 328 return;
319 329
320 // TODO(jhawkins): In WebKit, move value() and setValue() to 330 // TODO(jhawkins): In WebKit, move value() and setValue() to
321 // WebFormControlElement. 331 // WebFormControlElement.
322 string16 value; 332 string16 value;
323 if (element.formControlType() == WebString::fromUTF8("text") || 333 if (IsTextInput(input_element) ||
324 element.formControlType() == WebString::fromUTF8("hidden")) { 334 element.formControlType() == WebString::fromUTF8("hidden")) {
325 const WebInputElement& input_element = 335 value = input_element->value();
326 element.toConst<WebInputElement>();
327 value = input_element.value();
328 } else if (element.formControlType() == WebString::fromUTF8("select-one")) { 336 } else if (element.formControlType() == WebString::fromUTF8("select-one")) {
329 // TODO(jhawkins): This is ugly. WebSelectElement::value() is a non-const 337 // TODO(jhawkins): This is ugly. WebSelectElement::value() is a non-const
330 // method. Look into fixing this on the WebKit side. 338 // method. Look into fixing this on the WebKit side.
331 WebFormControlElement& e = const_cast<WebFormControlElement&>(element); 339 WebFormControlElement& e = const_cast<WebFormControlElement&>(element);
332 WebSelectElement select_element = e.to<WebSelectElement>(); 340 WebSelectElement select_element = e.to<WebSelectElement>();
333 value = select_element.value(); 341 value = select_element.value();
334 342
335 // Convert the |select_element| value to text if requested. 343 // Convert the |select_element| value to text if requested.
336 if (extract_mask & EXTRACT_OPTION_TEXT) { 344 if (extract_mask & EXTRACT_OPTION_TEXT) {
337 WebVector<WebElement> list_items = select_element.listItems(); 345 WebVector<WebElement> list_items = select_element.listItems();
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 WebVector<WebFormControlElement> control_elements; 418 WebVector<WebFormControlElement> control_elements;
411 element.getFormControlElements(control_elements); 419 element.getFormControlElements(control_elements);
412 420
413 // A vector of bools that indicate whether each field in the form meets the 421 // A vector of bools that indicate whether each field in the form meets the
414 // requirements and thus will be in the resulting |form|. 422 // requirements and thus will be in the resulting |form|.
415 std::vector<bool> fields_extracted(control_elements.size(), false); 423 std::vector<bool> fields_extracted(control_elements.size(), false);
416 424
417 for (size_t i = 0; i < control_elements.size(); ++i) { 425 for (size_t i = 0; i < control_elements.size(); ++i) {
418 const WebFormControlElement& control_element = control_elements[i]; 426 const WebFormControlElement& control_element = control_elements[i];
419 427
428 const WebInputElement* input_element =
429 WebInputElement::toWebInputElement(&control_element);
420 if (requirements & REQUIRE_AUTOCOMPLETE && 430 if (requirements & REQUIRE_AUTOCOMPLETE &&
421 control_element.formControlType() == WebString::fromUTF8("text")) { 431 IsTextInput(input_element)) {
422 const WebInputElement& input_element = 432 if (!input_element->autoComplete())
Ilya Sherman 2011/01/25 06:21:30 nit: No need for nested if-stmts here; you can com
honten.org 2011/01/25 06:38:28 Done.
423 control_element.toConst<WebInputElement>();
424 if (!input_element.autoComplete())
425 continue; 433 continue;
426 } 434 }
427 435
428 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) 436 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled())
429 continue; 437 continue;
430 438
431 // Create a new FormField, fill it out and map it to the field's name. 439 // Create a new FormField, fill it out and map it to the field's name.
432 FormField* field = new FormField; 440 FormField* field = new FormField;
433 WebFormControlElementToFormField(control_element, extract_mask, field); 441 WebFormControlElementToFormField(control_element, extract_mask, field);
434 form_fields.push_back(field); 442 form_fields.push_back(field);
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
624 return true; 632 return true;
625 } 633 }
626 634
627 bool FormManager::ClearFormWithNode(const WebNode& node) { 635 bool FormManager::ClearFormWithNode(const WebNode& node) {
628 FormElement* form_element = NULL; 636 FormElement* form_element = NULL;
629 if (!FindCachedFormElementWithNode(node, &form_element)) 637 if (!FindCachedFormElementWithNode(node, &form_element))
630 return false; 638 return false;
631 639
632 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 640 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
633 WebFormControlElement element = form_element->control_elements[i]; 641 WebFormControlElement element = form_element->control_elements[i];
634 if (element.formControlType() == WebString::fromUTF8("text")) { 642 WebInputElement* input_element =
635 643 WebInputElement::toWebInputElement(&element);
636 WebInputElement input_element = element.to<WebInputElement>(); 644 if (IsTextInput(input_element)) {
637 645
638 // We don't modify the value of disabled fields. 646 // We don't modify the value of disabled fields.
639 if (!input_element.isEnabled()) 647 if (!input_element->isEnabled())
640 continue; 648 continue;
641 649
642 input_element.setValue(string16()); 650 input_element->setValue(string16());
643 input_element.setAutofilled(false); 651 input_element->setAutofilled(false);
644 652
645 // Clearing the value in the focused node (above) can cause selection 653 // Clearing the value in the focused node (above) can cause selection
646 // to be lost. We force selection range to restore the text cursor. 654 // to be lost. We force selection range to restore the text cursor.
647 if (node == input_element) { 655 if (node == *input_element) {
648 int length = input_element.value().length(); 656 int length = input_element->value().length();
649 input_element.setSelectionRange(length, length); 657 input_element->setSelectionRange(length, length);
650 } 658 }
651 } else if (element.formControlType() == WebString::fromUTF8("select-one")) { 659 } else if (element.formControlType() == WebString::fromUTF8("select-one")) {
652 WebSelectElement select_element = element.to<WebSelectElement>(); 660 WebSelectElement select_element = element.to<WebSelectElement>();
653 select_element.setValue(form_element->control_values[i]); 661 select_element.setValue(form_element->control_values[i]);
654 } 662 }
655 } 663 }
656 664
657 return true; 665 return true;
658 } 666 }
659 667
660 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node, 668 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node,
661 bool was_autofilled) { 669 bool was_autofilled) {
662 FormElement* form_element = NULL; 670 FormElement* form_element = NULL;
663 if (!FindCachedFormElementWithNode(node, &form_element)) 671 if (!FindCachedFormElementWithNode(node, &form_element))
664 return false; 672 return false;
665 673
666 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 674 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
667 WebFormControlElement* element = &form_element->control_elements[i]; 675 WebInputElement* input_element =
668 676 WebInputElement::toWebInputElement(&form_element->control_elements[i]);
669 // Only input elements can be previewed. 677 // Only input elements can be previewed.
670 if (element->formControlType() != WebString::fromUTF8("text")) 678 if (!IsTextInput(input_element))
671 continue; 679 continue;
672 680
673 // If the input element has not been auto-filled, FormManager has not 681 // If the input element has not been auto-filled, FormManager has not
674 // previewed this field, so we have nothing to reset. 682 // previewed this field, so we have nothing to reset.
675 WebInputElement input_element = element->to<WebInputElement>(); 683 if (!input_element->isAutofilled())
676 if (!input_element.isAutofilled())
677 continue; 684 continue;
678 685
679 // There might be unrelated elements in this form which have already been 686 // There might be unrelated elements in this form which have already been
680 // auto-filled. For example, the user might have already filled the address 687 // auto-filled. For example, the user might have already filled the address
681 // part of a form and now be dealing with the credit card section. We only 688 // part of a form and now be dealing with the credit card section. We only
682 // want to reset the auto-filled status for fields that were previewed. 689 // want to reset the auto-filled status for fields that were previewed.
683 if (input_element.suggestedValue().isEmpty()) 690 if (input_element->suggestedValue().isEmpty())
684 continue; 691 continue;
685 692
686 // Clear the suggested value. For the initiating node, also restore the 693 // Clear the suggested value. For the initiating node, also restore the
687 // original value. 694 // original value.
688 input_element.setSuggestedValue(WebString()); 695 input_element->setSuggestedValue(WebString());
689 bool is_initiating_node = (node == input_element); 696 bool is_initiating_node = (node == *input_element);
690 if (is_initiating_node) { 697 if (is_initiating_node) {
691 // Call |setValue()| to force the renderer to update the field's displayed 698 // Call |setValue()| to force the renderer to update the field's displayed
692 // value. 699 // value.
693 input_element.setValue(input_element.value()); 700 input_element->setValue(input_element->value());
694 input_element.setAutofilled(was_autofilled); 701 input_element->setAutofilled(was_autofilled);
695 } else { 702 } else {
696 input_element.setAutofilled(false); 703 input_element->setAutofilled(false);
697 } 704 }
698 705
699 // Clearing the suggested value in the focused node (above) can cause 706 // Clearing the suggested value in the focused node (above) can cause
700 // selection to be lost. We force selection range to restore the text 707 // selection to be lost. We force selection range to restore the text
701 // cursor. 708 // cursor.
702 if (is_initiating_node) { 709 if (is_initiating_node) {
703 int length = input_element.value().length(); 710 int length = input_element->value().length();
704 input_element.setSelectionRange(length, length); 711 input_element->setSelectionRange(length, length);
705 } 712 }
706 } 713 }
707 714
708 return true; 715 return true;
709 } 716 }
710 717
711 void FormManager::Reset() { 718 void FormManager::Reset() {
712 STLDeleteElements(&form_elements_); 719 STLDeleteElements(&form_elements_);
713 } 720 }
714 721
715 void FormManager::ResetFrame(const WebFrame* frame) { 722 void FormManager::ResetFrame(const WebFrame* frame) {
716 FormElementList::iterator iter = form_elements_.begin(); 723 FormElementList::iterator iter = form_elements_.begin();
717 while (iter != form_elements_.end()) { 724 while (iter != form_elements_.end()) {
718 if ((*iter)->form_element.document().frame() == frame) { 725 if ((*iter)->form_element.document().frame() == frame) {
719 delete *iter; 726 delete *iter;
720 iter = form_elements_.erase(iter); 727 iter = form_elements_.erase(iter);
721 } else { 728 } else {
722 ++iter; 729 ++iter;
723 } 730 }
724 } 731 }
725 } 732 }
726 733
727 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) { 734 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) {
728 FormElement* form_element = NULL; 735 FormElement* form_element = NULL;
729 if (!FindCachedFormElementWithNode(node, &form_element)) 736 if (!FindCachedFormElementWithNode(node, &form_element))
730 return false; 737 return false;
731 738
732 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { 739 for (size_t i = 0; i < form_element->control_elements.size(); ++i) {
733 WebFormControlElement element = form_element->control_elements[i]; 740 WebInputElement* input_element =
734 if (element.formControlType() != WebString::fromUTF8("text")) 741 WebInputElement::toWebInputElement(&form_element->control_elements[i]);
742 if (!IsTextInput(input_element))
735 continue; 743 continue;
736 744
737 const WebInputElement& input_element = element.to<WebInputElement>(); 745 if (input_element->isAutofilled())
738 if (input_element.isAutofilled())
739 return true; 746 return true;
740 } 747 }
741 748
742 return false; 749 return false;
743 } 750 }
744 751
745 // static 752 // static
746 string16 FormManager::InferLabelForElement( 753 string16 FormManager::InferLabelForElement(
747 const WebFormControlElement& element) { 754 const WebFormControlElement& element) {
748 // Don't scrape labels for hidden elements. 755 // Don't scrape labels for hidden elements.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 if (k >= data.fields.size()) 844 if (k >= data.fields.size())
838 continue; 845 continue;
839 846
840 DCHECK_EQ(data.fields[k].name(), element_name); 847 DCHECK_EQ(data.fields[k].name(), element_name);
841 848
842 bool is_initiating_node = false; 849 bool is_initiating_node = false;
843 850
844 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or 851 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or
845 // REQUIRE_EMPTY, which both require text form control elements, so special- 852 // REQUIRE_EMPTY, which both require text form control elements, so special-
846 // case this type of element. 853 // case this type of element.
847 if (element->formControlType() == WebString::fromUTF8("text")) { 854 const WebInputElement* input_element =
848 const WebInputElement& input_element = 855 WebInputElement::toWebInputElement(element);
849 element->toConst<WebInputElement>(); 856 if (IsTextInput(input_element)) {
850 857
851 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete 858 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete
852 // attribute for select control elements, but it probably should. 859 // attribute for select control elements, but it probably should.
853 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element.autoComplete()) 860 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete())
854 continue; 861 continue;
855 862
856 is_initiating_node = (input_element == node); 863 is_initiating_node = (*input_element == node);
857 // Don't require the node that initiated the auto-fill process to be 864 // Don't require the node that initiated the auto-fill process to be
858 // empty. The user is typing in this field and we should complete the 865 // empty. The user is typing in this field and we should complete the
859 // value when the user selects a value to fill out. 866 // value when the user selects a value to fill out.
860 if (requirements & REQUIRE_EMPTY && 867 if (requirements & REQUIRE_EMPTY &&
861 !is_initiating_node && 868 !is_initiating_node &&
862 !input_element.value().isEmpty()) 869 !input_element->value().isEmpty())
863 continue; 870 continue;
864 } 871 }
865 872
866 if (requirements & REQUIRE_ENABLED && !element->isEnabled()) 873 if (requirements & REQUIRE_ENABLED && !element->isEnabled())
867 continue; 874 continue;
868 875
869 callback->Run(element, &data.fields[k], is_initiating_node); 876 callback->Run(element, &data.fields[k], is_initiating_node);
870 877
871 // We found a matching form field so move on to the next. 878 // We found a matching form field so move on to the next.
872 ++j; 879 ++j;
873 } 880 }
874 881
875 delete callback; 882 delete callback;
876 } 883 }
877 884
878 void FormManager::FillFormField(WebFormControlElement* field, 885 void FormManager::FillFormField(WebFormControlElement* field,
879 const FormField* data, 886 const FormField* data,
880 bool is_initiating_node) { 887 bool is_initiating_node) {
881 // Nothing to fill. 888 // Nothing to fill.
882 if (data->value().empty()) 889 if (data->value().empty())
883 return; 890 return;
884 891
885 if (field->formControlType() == WebString::fromUTF8("text")) { 892 WebInputElement* input_element = WebInputElement::toWebInputElement(field);
886 WebInputElement input_element = field->to<WebInputElement>(); 893 if (IsTextInput(input_element)) {
887 894
888 // If the maxlength attribute contains a negative value, maxLength() 895 // If the maxlength attribute contains a negative value, maxLength()
889 // returns the default maxlength value. 896 // returns the default maxlength value.
890 input_element.setValue(data->value().substr(0, input_element.maxLength())); 897 input_element->setValue(
891 input_element.setAutofilled(true); 898 data->value().substr(0, input_element->maxLength()));
899 input_element->setAutofilled(true);
892 if (is_initiating_node) { 900 if (is_initiating_node) {
893 int length = input_element.value().length(); 901 int length = input_element->value().length();
894 input_element.setSelectionRange(length, length); 902 input_element->setSelectionRange(length, length);
895 } 903 }
896 } else if (field->formControlType() == WebString::fromUTF8("select-one")) { 904 } else if (field->formControlType() == WebString::fromUTF8("select-one")) {
897 WebSelectElement select_element = field->to<WebSelectElement>(); 905 WebSelectElement select_element = field->to<WebSelectElement>();
898 select_element.setValue(data->value()); 906 select_element.setValue(data->value());
899 } 907 }
900 } 908 }
901 909
902 void FormManager::PreviewFormField(WebFormControlElement* field, 910 void FormManager::PreviewFormField(WebFormControlElement* field,
903 const FormField* data, 911 const FormField* data,
904 bool is_initiating_node) { 912 bool is_initiating_node) {
905 // Nothing to preview. 913 // Nothing to preview.
906 if (data->value().empty()) 914 if (data->value().empty())
907 return; 915 return;
908 916
909 // Only preview input fields. 917 // Only preview input fields.
910 if (field->formControlType() != WebString::fromUTF8("text")) 918 WebInputElement* input_element = WebInputElement::toWebInputElement(field);
919 if (!IsTextInput(input_element))
911 return; 920 return;
912 921
913 WebInputElement input_element = field->to<WebInputElement>();
914
915 // If the maxlength attribute contains a negative value, maxLength() 922 // If the maxlength attribute contains a negative value, maxLength()
916 // returns the default maxlength value. 923 // returns the default maxlength value.
917 input_element.setSuggestedValue( 924 input_element->setSuggestedValue(
918 data->value().substr(0, input_element.maxLength())); 925 data->value().substr(0, input_element->maxLength()));
919 input_element.setAutofilled(true); 926 input_element->setAutofilled(true);
920 if (is_initiating_node) 927 if (is_initiating_node)
921 input_element.setSelectionRange(0, input_element.suggestedValue().length()); 928 input_element->setSelectionRange(0,
929 input_element->suggestedValue().length());
Ilya Sherman 2011/01/25 06:21:30 nit: Please indent this line so that the leading "
honten.org 2011/01/25 06:38:28 Done.
922 } 930 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698