OLD | NEW |
---|---|
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 Loading... | |
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) { | |
Ilya Sherman
2011/01/28 08:15:52
nit: Just noticed: no need for "static" here, as i
honten.org
2011/01/29 03:43:30
Done.
| |
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 Loading... | |
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 Loading... | |
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) && !input_element->autoComplete()) |
422 const WebInputElement& input_element = | 432 continue; |
423 control_element.toConst<WebInputElement>(); | |
424 if (!input_element.autoComplete()) | |
425 continue; | |
426 } | |
427 | 433 |
428 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) | 434 if (requirements & REQUIRE_ENABLED && !control_element.isEnabled()) |
429 continue; | 435 continue; |
430 | 436 |
431 // Create a new FormField, fill it out and map it to the field's name. | 437 // Create a new FormField, fill it out and map it to the field's name. |
432 FormField* field = new FormField; | 438 FormField* field = new FormField; |
433 WebFormControlElementToFormField(control_element, extract_mask, field); | 439 WebFormControlElementToFormField(control_element, extract_mask, field); |
434 form_fields.push_back(field); | 440 form_fields.push_back(field); |
435 // TODO(jhawkins): A label element is mapped to a form control element's id. | 441 // TODO(jhawkins): A label element is mapped to a form control element's id. |
436 // field->name() will contain the id only if the name does not exist. Add | 442 // field->name() will contain the id only if the name does not exist. Add |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
624 return true; | 630 return true; |
625 } | 631 } |
626 | 632 |
627 bool FormManager::ClearFormWithNode(const WebNode& node) { | 633 bool FormManager::ClearFormWithNode(const WebNode& node) { |
628 FormElement* form_element = NULL; | 634 FormElement* form_element = NULL; |
629 if (!FindCachedFormElementWithNode(node, &form_element)) | 635 if (!FindCachedFormElementWithNode(node, &form_element)) |
630 return false; | 636 return false; |
631 | 637 |
632 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { | 638 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { |
633 WebFormControlElement element = form_element->control_elements[i]; | 639 WebFormControlElement element = form_element->control_elements[i]; |
634 if (element.formControlType() == WebString::fromUTF8("text")) { | 640 WebInputElement* input_element = |
635 | 641 WebInputElement::toWebInputElement(&element); |
636 WebInputElement input_element = element.to<WebInputElement>(); | 642 if (IsTextInput(input_element)) { |
637 | 643 |
638 // We don't modify the value of disabled fields. | 644 // We don't modify the value of disabled fields. |
639 if (!input_element.isEnabled()) | 645 if (!input_element->isEnabled()) |
640 continue; | 646 continue; |
641 | 647 |
642 input_element.setValue(string16()); | 648 input_element->setValue(string16()); |
643 input_element.setAutofilled(false); | 649 input_element->setAutofilled(false); |
644 | 650 |
645 // Clearing the value in the focused node (above) can cause selection | 651 // Clearing the value in the focused node (above) can cause selection |
646 // to be lost. We force selection range to restore the text cursor. | 652 // to be lost. We force selection range to restore the text cursor. |
647 if (node == input_element) { | 653 if (node == *input_element) { |
648 int length = input_element.value().length(); | 654 int length = input_element->value().length(); |
649 input_element.setSelectionRange(length, length); | 655 input_element->setSelectionRange(length, length); |
650 } | 656 } |
651 } else if (element.formControlType() == WebString::fromUTF8("select-one")) { | 657 } else if (element.formControlType() == WebString::fromUTF8("select-one")) { |
652 WebSelectElement select_element = element.to<WebSelectElement>(); | 658 WebSelectElement select_element = element.to<WebSelectElement>(); |
653 select_element.setValue(form_element->control_values[i]); | 659 select_element.setValue(form_element->control_values[i]); |
654 } | 660 } |
655 } | 661 } |
656 | 662 |
657 return true; | 663 return true; |
658 } | 664 } |
659 | 665 |
660 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node, | 666 bool FormManager::ClearPreviewedFormWithNode(const WebNode& node, |
661 bool was_autofilled) { | 667 bool was_autofilled) { |
662 FormElement* form_element = NULL; | 668 FormElement* form_element = NULL; |
663 if (!FindCachedFormElementWithNode(node, &form_element)) | 669 if (!FindCachedFormElementWithNode(node, &form_element)) |
664 return false; | 670 return false; |
665 | 671 |
666 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { | 672 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { |
667 WebFormControlElement* element = &form_element->control_elements[i]; | 673 WebInputElement* input_element = |
668 | 674 WebInputElement::toWebInputElement(&form_element->control_elements[i]); |
669 // Only input elements can be previewed. | 675 // Only input elements can be previewed. |
670 if (element->formControlType() != WebString::fromUTF8("text")) | 676 if (!IsTextInput(input_element)) |
671 continue; | 677 continue; |
672 | 678 |
673 // If the input element has not been auto-filled, FormManager has not | 679 // If the input element has not been auto-filled, FormManager has not |
674 // previewed this field, so we have nothing to reset. | 680 // previewed this field, so we have nothing to reset. |
675 WebInputElement input_element = element->to<WebInputElement>(); | 681 if (!input_element->isAutofilled()) |
676 if (!input_element.isAutofilled()) | |
677 continue; | 682 continue; |
678 | 683 |
679 // There might be unrelated elements in this form which have already been | 684 // 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 | 685 // 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 | 686 // 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. | 687 // want to reset the auto-filled status for fields that were previewed. |
683 if (input_element.suggestedValue().isEmpty()) | 688 if (input_element->suggestedValue().isEmpty()) |
684 continue; | 689 continue; |
685 | 690 |
686 // Clear the suggested value. For the initiating node, also restore the | 691 // Clear the suggested value. For the initiating node, also restore the |
687 // original value. | 692 // original value. |
688 input_element.setSuggestedValue(WebString()); | 693 input_element->setSuggestedValue(WebString()); |
689 bool is_initiating_node = (node == input_element); | 694 bool is_initiating_node = (node == *input_element); |
690 if (is_initiating_node) { | 695 if (is_initiating_node) { |
691 // Call |setValue()| to force the renderer to update the field's displayed | 696 // Call |setValue()| to force the renderer to update the field's displayed |
692 // value. | 697 // value. |
693 input_element.setValue(input_element.value()); | 698 input_element->setValue(input_element->value()); |
694 input_element.setAutofilled(was_autofilled); | 699 input_element->setAutofilled(was_autofilled); |
695 } else { | 700 } else { |
696 input_element.setAutofilled(false); | 701 input_element->setAutofilled(false); |
697 } | 702 } |
698 | 703 |
699 // Clearing the suggested value in the focused node (above) can cause | 704 // Clearing the suggested value in the focused node (above) can cause |
700 // selection to be lost. We force selection range to restore the text | 705 // selection to be lost. We force selection range to restore the text |
701 // cursor. | 706 // cursor. |
702 if (is_initiating_node) { | 707 if (is_initiating_node) { |
703 int length = input_element.value().length(); | 708 int length = input_element->value().length(); |
704 input_element.setSelectionRange(length, length); | 709 input_element->setSelectionRange(length, length); |
705 } | 710 } |
706 } | 711 } |
707 | 712 |
708 return true; | 713 return true; |
709 } | 714 } |
710 | 715 |
711 void FormManager::Reset() { | 716 void FormManager::Reset() { |
712 STLDeleteElements(&form_elements_); | 717 STLDeleteElements(&form_elements_); |
713 } | 718 } |
714 | 719 |
715 void FormManager::ResetFrame(const WebFrame* frame) { | 720 void FormManager::ResetFrame(const WebFrame* frame) { |
716 FormElementList::iterator iter = form_elements_.begin(); | 721 FormElementList::iterator iter = form_elements_.begin(); |
717 while (iter != form_elements_.end()) { | 722 while (iter != form_elements_.end()) { |
718 if ((*iter)->form_element.document().frame() == frame) { | 723 if ((*iter)->form_element.document().frame() == frame) { |
719 delete *iter; | 724 delete *iter; |
720 iter = form_elements_.erase(iter); | 725 iter = form_elements_.erase(iter); |
721 } else { | 726 } else { |
722 ++iter; | 727 ++iter; |
723 } | 728 } |
724 } | 729 } |
725 } | 730 } |
726 | 731 |
727 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) { | 732 bool FormManager::FormWithNodeIsAutoFilled(const WebNode& node) { |
728 FormElement* form_element = NULL; | 733 FormElement* form_element = NULL; |
729 if (!FindCachedFormElementWithNode(node, &form_element)) | 734 if (!FindCachedFormElementWithNode(node, &form_element)) |
730 return false; | 735 return false; |
731 | 736 |
732 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { | 737 for (size_t i = 0; i < form_element->control_elements.size(); ++i) { |
733 WebFormControlElement element = form_element->control_elements[i]; | 738 WebInputElement* input_element = |
734 if (element.formControlType() != WebString::fromUTF8("text")) | 739 WebInputElement::toWebInputElement(&form_element->control_elements[i]); |
740 if (!IsTextInput(input_element)) | |
735 continue; | 741 continue; |
736 | 742 |
737 const WebInputElement& input_element = element.to<WebInputElement>(); | 743 if (input_element->isAutofilled()) |
738 if (input_element.isAutofilled()) | |
739 return true; | 744 return true; |
740 } | 745 } |
741 | 746 |
742 return false; | 747 return false; |
743 } | 748 } |
744 | 749 |
745 // static | 750 // static |
746 string16 FormManager::InferLabelForElement( | 751 string16 FormManager::InferLabelForElement( |
747 const WebFormControlElement& element) { | 752 const WebFormControlElement& element) { |
748 // Don't scrape labels for hidden elements. | 753 // Don't scrape labels for hidden elements. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
837 if (k >= data.fields.size()) | 842 if (k >= data.fields.size()) |
838 continue; | 843 continue; |
839 | 844 |
840 DCHECK_EQ(data.fields[k].name(), element_name); | 845 DCHECK_EQ(data.fields[k].name(), element_name); |
841 | 846 |
842 bool is_initiating_node = false; | 847 bool is_initiating_node = false; |
843 | 848 |
844 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or | 849 // More than likely |requirements| will contain REQUIRE_AUTOCOMPLETE and/or |
845 // REQUIRE_EMPTY, which both require text form control elements, so special- | 850 // REQUIRE_EMPTY, which both require text form control elements, so special- |
846 // case this type of element. | 851 // case this type of element. |
847 if (element->formControlType() == WebString::fromUTF8("text")) { | 852 const WebInputElement* input_element = |
848 const WebInputElement& input_element = | 853 WebInputElement::toWebInputElement(element); |
849 element->toConst<WebInputElement>(); | 854 if (IsTextInput(input_element)) { |
850 | 855 |
851 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete | 856 // TODO(jhawkins): WebKit currently doesn't handle the autocomplete |
852 // attribute for select control elements, but it probably should. | 857 // attribute for select control elements, but it probably should. |
853 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element.autoComplete()) | 858 if (requirements & REQUIRE_AUTOCOMPLETE && !input_element->autoComplete()) |
854 continue; | 859 continue; |
855 | 860 |
856 is_initiating_node = (input_element == node); | 861 is_initiating_node = (*input_element == node); |
857 // Don't require the node that initiated the auto-fill process to be | 862 // 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 | 863 // empty. The user is typing in this field and we should complete the |
859 // value when the user selects a value to fill out. | 864 // value when the user selects a value to fill out. |
860 if (requirements & REQUIRE_EMPTY && | 865 if (requirements & REQUIRE_EMPTY && |
861 !is_initiating_node && | 866 !is_initiating_node && |
862 !input_element.value().isEmpty()) | 867 !input_element->value().isEmpty()) |
863 continue; | 868 continue; |
864 } | 869 } |
865 | 870 |
866 if (requirements & REQUIRE_ENABLED && !element->isEnabled()) | 871 if (requirements & REQUIRE_ENABLED && !element->isEnabled()) |
867 continue; | 872 continue; |
868 | 873 |
869 callback->Run(element, &data.fields[k], is_initiating_node); | 874 callback->Run(element, &data.fields[k], is_initiating_node); |
870 | 875 |
871 // We found a matching form field so move on to the next. | 876 // We found a matching form field so move on to the next. |
872 ++j; | 877 ++j; |
873 } | 878 } |
874 | 879 |
875 delete callback; | 880 delete callback; |
876 } | 881 } |
877 | 882 |
878 void FormManager::FillFormField(WebFormControlElement* field, | 883 void FormManager::FillFormField(WebFormControlElement* field, |
879 const FormField* data, | 884 const FormField* data, |
880 bool is_initiating_node) { | 885 bool is_initiating_node) { |
881 // Nothing to fill. | 886 // Nothing to fill. |
882 if (data->value().empty()) | 887 if (data->value().empty()) |
883 return; | 888 return; |
884 | 889 |
885 if (field->formControlType() == WebString::fromUTF8("text")) { | 890 WebInputElement* input_element = WebInputElement::toWebInputElement(field); |
886 WebInputElement input_element = field->to<WebInputElement>(); | 891 if (IsTextInput(input_element)) { |
887 | 892 |
888 // If the maxlength attribute contains a negative value, maxLength() | 893 // If the maxlength attribute contains a negative value, maxLength() |
889 // returns the default maxlength value. | 894 // returns the default maxlength value. |
890 input_element.setValue(data->value().substr(0, input_element.maxLength())); | 895 input_element->setValue( |
891 input_element.setAutofilled(true); | 896 data->value().substr(0, input_element->maxLength())); |
897 input_element->setAutofilled(true); | |
892 if (is_initiating_node) { | 898 if (is_initiating_node) { |
893 int length = input_element.value().length(); | 899 int length = input_element->value().length(); |
894 input_element.setSelectionRange(length, length); | 900 input_element->setSelectionRange(length, length); |
895 } | 901 } |
896 } else if (field->formControlType() == WebString::fromUTF8("select-one")) { | 902 } else if (field->formControlType() == WebString::fromUTF8("select-one")) { |
897 WebSelectElement select_element = field->to<WebSelectElement>(); | 903 WebSelectElement select_element = field->to<WebSelectElement>(); |
898 select_element.setValue(data->value()); | 904 select_element.setValue(data->value()); |
899 } | 905 } |
900 } | 906 } |
901 | 907 |
902 void FormManager::PreviewFormField(WebFormControlElement* field, | 908 void FormManager::PreviewFormField(WebFormControlElement* field, |
903 const FormField* data, | 909 const FormField* data, |
904 bool is_initiating_node) { | 910 bool is_initiating_node) { |
905 // Nothing to preview. | 911 // Nothing to preview. |
906 if (data->value().empty()) | 912 if (data->value().empty()) |
907 return; | 913 return; |
908 | 914 |
909 // Only preview input fields. | 915 // Only preview input fields. |
910 if (field->formControlType() != WebString::fromUTF8("text")) | 916 WebInputElement* input_element = WebInputElement::toWebInputElement(field); |
917 if (!IsTextInput(input_element)) | |
911 return; | 918 return; |
912 | 919 |
913 WebInputElement input_element = field->to<WebInputElement>(); | |
914 | |
915 // If the maxlength attribute contains a negative value, maxLength() | 920 // If the maxlength attribute contains a negative value, maxLength() |
916 // returns the default maxlength value. | 921 // returns the default maxlength value. |
917 input_element.setSuggestedValue( | 922 input_element->setSuggestedValue( |
918 data->value().substr(0, input_element.maxLength())); | 923 data->value().substr(0, input_element->maxLength())); |
919 input_element.setAutofilled(true); | 924 input_element->setAutofilled(true); |
920 if (is_initiating_node) | 925 if (is_initiating_node) |
921 input_element.setSelectionRange(0, input_element.suggestedValue().length()); | 926 input_element->setSelectionRange(0, |
927 input_element->suggestedValue().length()); | |
922 } | 928 } |
OLD | NEW |