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

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLSelectElement.cpp

Issue 2134553002: SELECT element: Remove optionIndex argument of HTMLSelectElement::selectOption(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 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
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLSelectElement.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 /* 1 /*
2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
4 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 1999 Antti Koivisto (koivisto@kde.org)
5 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) 7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com)
8 * Copyright (C) 2010 Google Inc. All rights reserved. 8 * Copyright (C) 2010 Google Inc. All rights reserved.
9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/) 9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/)
10 * 10 *
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 138
139 // Bail out if this index is already the selected one, to avoid running 139 // Bail out if this index is already the selected one, to avoid running
140 // unnecessary JavaScript that can mess up autofill when there is no actual 140 // unnecessary JavaScript that can mess up autofill when there is no actual
141 // change (see https://bugs.webkit.org/show_bug.cgi?id=35256 and 141 // change (see https://bugs.webkit.org/show_bug.cgi?id=35256 and
142 // <rdar://7467917>). The selectOption function does not behave this way, 142 // <rdar://7467917>). The selectOption function does not behave this way,
143 // possibly because other callers need a change event even in cases where 143 // possibly because other callers need a change event even in cases where
144 // the selected option is not change. 144 // the selected option is not change.
145 if (optionIndex == selectedIndex()) 145 if (optionIndex == selectedIndex())
146 return; 146 return;
147 147
148 selectOption(optionIndex, DeselectOtherOptions | MakeOptionDirty | (fireOnCh angeNow ? DispatchInputAndChangeEvent : 0)); 148 selectOption(item(optionIndex), DeselectOtherOptions | MakeOptionDirty | (fi reOnChangeNow ? DispatchInputAndChangeEvent : 0));
149 } 149 }
150 150
151 bool HTMLSelectElement::hasPlaceholderLabelOption() const 151 bool HTMLSelectElement::hasPlaceholderLabelOption() const
152 { 152 {
153 // The select element has no placeholder label option if it has an attribute 153 // The select element has no placeholder label option if it has an attribute
154 // "multiple" specified or a display size of non-1. 154 // "multiple" specified or a display size of non-1.
155 // 155 //
156 // The condition "size() > 1" is not compliant with the HTML5 spec as of Dec 156 // The condition "size() > 1" is not compliant with the HTML5 spec as of Dec
157 // 3, 2010. "size() != 1" is correct. Using "size() > 1" here because 157 // 3, 2010. "size() != 1" is correct. Using "size() > 1" here because
158 // size() may be 0 in WebKit. See the discussion at 158 // size() may be 0 in WebKit. See the discussion at
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 if (HTMLOptionElement* option = selectedOption()) 276 if (HTMLOptionElement* option = selectedOption())
277 return option->value(); 277 return option->value();
278 return ""; 278 return "";
279 } 279 }
280 280
281 void HTMLSelectElement::setValue(const String &value, bool sendEvents) 281 void HTMLSelectElement::setValue(const String &value, bool sendEvents)
282 { 282 {
283 // We clear the previously selected option(s) when needed, to guarantee 283 // We clear the previously selected option(s) when needed, to guarantee
284 // calling setSelectedIndex() only once. 284 // calling setSelectedIndex() only once.
285 int optionIndex = 0; 285 int optionIndex = 0;
286 HTMLOptionElement* option = nullptr;
286 if (value.isNull()) { 287 if (value.isNull()) {
287 optionIndex = -1; 288 optionIndex = -1;
288 } else { 289 } else {
289 // Find the option with value() matching the given parameter and make it 290 // Find the option with value() matching the given parameter and make it
290 // the current selection. 291 // the current selection.
291 for (auto& item : listItems()) { 292 for (auto& item : listItems()) {
292 if (!isHTMLOptionElement(item)) 293 if (!isHTMLOptionElement(item))
293 continue; 294 continue;
294 if (toHTMLOptionElement(item)->value() == value) 295 if (toHTMLOptionElement(item)->value() == value) {
296 option = toHTMLOptionElement(item);
295 break; 297 break;
298 }
296 optionIndex++; 299 optionIndex++;
297 } 300 }
298 if (optionIndex >= static_cast<int>(listItems().size())) 301 if (optionIndex >= static_cast<int>(listItems().size()))
299 optionIndex = -1; 302 optionIndex = -1;
300 } 303 }
301 304
302 int previousSelectedIndex = selectedIndex(); 305 int previousSelectedIndex = selectedIndex();
303 setSuggestedOption(nullptr); 306 setSuggestedOption(nullptr);
304 if (m_isAutofilledByPreview) 307 if (m_isAutofilledByPreview)
305 setAutofilled(false); 308 setAutofilled(false);
306 SelectOptionFlags flags = DeselectOtherOptions | MakeOptionDirty; 309 SelectOptionFlags flags = DeselectOtherOptions | MakeOptionDirty;
307 if (sendEvents) 310 if (sendEvents)
308 flags |= DispatchInputAndChangeEvent; 311 flags |= DispatchInputAndChangeEvent;
309 selectOption(optionIndex, flags); 312 selectOption(option, flags);
310 313
311 if (sendEvents && previousSelectedIndex != selectedIndex() && !usesMenuList( )) 314 if (sendEvents && previousSelectedIndex != selectedIndex() && !usesMenuList( ))
312 listBoxOnChange(); 315 listBoxOnChange();
313 } 316 }
314 317
315 String HTMLSelectElement::suggestedValue() const 318 String HTMLSelectElement::suggestedValue() const
316 { 319 {
317 return m_suggestedOption ? m_suggestedOption->value() : ""; 320 return m_suggestedOption ? m_suggestedOption->value() : "";
318 } 321 }
319 322
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after
873 currentElement = ElementTraversal::nextSkippingChildren(*currentElement, this); 876 currentElement = ElementTraversal::nextSkippingChildren(*currentElement, this);
874 } 877 }
875 } 878 }
876 879
877 void HTMLSelectElement::resetToDefaultSelection(ResetReason reason) 880 void HTMLSelectElement::resetToDefaultSelection(ResetReason reason)
878 { 881 {
879 // https://html.spec.whatwg.org/multipage/forms.html#ask-for-a-reset 882 // https://html.spec.whatwg.org/multipage/forms.html#ask-for-a-reset
880 if (multiple()) 883 if (multiple())
881 return; 884 return;
882 HTMLOptionElement* firstEnabledOption = nullptr; 885 HTMLOptionElement* firstEnabledOption = nullptr;
883 int firstEnabledOptionIndex = -1;
884 HTMLOptionElement* lastSelectedOption = nullptr; 886 HTMLOptionElement* lastSelectedOption = nullptr;
885 bool didChange = false; 887 bool didChange = false;
886 int optionIndex = 0; 888 int optionIndex = 0;
887 // We can't use HTMLSelectElement::options here because this function is 889 // We can't use HTMLSelectElement::options here because this function is
888 // called in Node::insertedInto and Node::removedFrom before invalidating 890 // called in Node::insertedInto and Node::removedFrom before invalidating
889 // node collections. 891 // node collections.
890 for (const auto& option : optionList()) { 892 for (const auto& option : optionList()) {
891 if (option->selected()) { 893 if (option->selected()) {
892 if (lastSelectedOption) { 894 if (lastSelectedOption) {
893 lastSelectedOption->setSelectedState(false); 895 lastSelectedOption->setSelectedState(false);
894 didChange = true; 896 didChange = true;
895 } 897 }
896 lastSelectedOption = option; 898 lastSelectedOption = option;
897 } 899 }
898 if (!firstEnabledOption && !option->isDisabledFormControl()) { 900 if (!firstEnabledOption && !option->isDisabledFormControl()) {
899 firstEnabledOption = option; 901 firstEnabledOption = option;
900 firstEnabledOptionIndex = optionIndex;
901 if (reason == ResetReasonSelectedOptionRemoved) { 902 if (reason == ResetReasonSelectedOptionRemoved) {
902 // There must be no selected OPTIONs. 903 // There must be no selected OPTIONs.
903 break; 904 break;
904 } 905 }
905 } 906 }
906 ++optionIndex; 907 ++optionIndex;
907 } 908 }
908 if (!lastSelectedOption && m_size <= 1 && firstEnabledOption && !firstEnable dOption->selected()) { 909 if (!lastSelectedOption && m_size <= 1 && firstEnabledOption && !firstEnable dOption->selected()) {
909 selectOption(firstEnabledOption, firstEnabledOptionIndex, reason == Rese tReasonSelectedOptionRemoved ? 0 : DeselectOtherOptions); 910 selectOption(firstEnabledOption, reason == ResetReasonSelectedOptionRemo ved ? 0 : DeselectOtherOptions);
910 lastSelectedOption = firstEnabledOption; 911 lastSelectedOption = firstEnabledOption;
911 didChange = true; 912 didChange = true;
912 } 913 }
913 if (didChange) 914 if (didChange)
914 setNeedsValidityCheck(); 915 setNeedsValidityCheck();
915 m_lastOnChangeOption = lastSelectedOption; 916 m_lastOnChangeOption = lastSelectedOption;
916 } 917 }
917 918
918 HTMLOptionElement* HTMLSelectElement::selectedOption() const 919 HTMLOptionElement* HTMLSelectElement::selectedOption() const
919 { 920 {
(...skipping 15 matching lines...) Expand all
935 if (toHTMLOptionElement(*element).selected()) 936 if (toHTMLOptionElement(*element).selected())
936 return index; 937 return index;
937 ++index; 938 ++index;
938 } 939 }
939 940
940 return -1; 941 return -1;
941 } 942 }
942 943
943 void HTMLSelectElement::setSelectedIndex(int index) 944 void HTMLSelectElement::setSelectedIndex(int index)
944 { 945 {
945 selectOption(index, DeselectOtherOptions | MakeOptionDirty); 946 selectOption(item(index), DeselectOtherOptions | MakeOptionDirty);
946 } 947 }
947 948
948 void HTMLSelectElement::setSuggestedOption(HTMLOptionElement* option) 949 void HTMLSelectElement::setSuggestedOption(HTMLOptionElement* option)
949 { 950 {
950 if (m_suggestedOption == option) 951 if (m_suggestedOption == option)
951 return; 952 return;
952 m_suggestedOption = option; 953 m_suggestedOption = option;
953 954
954 if (LayoutObject* layoutObject = this->layoutObject()) { 955 if (LayoutObject* layoutObject = this->layoutObject()) {
955 layoutObject->updateFromElement(); 956 layoutObject->updateFromElement();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
1044 setNeedsValidityCheck(); 1045 setNeedsValidityCheck();
1045 m_lastOnChangeSelection.clear(); 1046 m_lastOnChangeSelection.clear();
1046 } 1047 }
1047 1048
1048 void HTMLSelectElement::hrInsertedOrRemoved(HTMLHRElement& hr) 1049 void HTMLSelectElement::hrInsertedOrRemoved(HTMLHRElement& hr)
1049 { 1050 {
1050 setRecalcListItems(hr); 1051 setRecalcListItems(hr);
1051 m_lastOnChangeSelection.clear(); 1052 m_lastOnChangeSelection.clear();
1052 } 1053 }
1053 1054
1054 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
1055 {
1056 selectOption(optionIndex < 0 ? nullptr : item(optionIndex), flags);
1057 }
1058
1059 void HTMLSelectElement::selectOption(HTMLOptionElement* option, SelectOptionFlag s flags)
1060 {
1061 selectOption(option, option ? option->index() : -1, flags);
1062 }
1063
1064 // TODO(tkent): This function is not efficient. It contains multiple O(N) 1055 // TODO(tkent): This function is not efficient. It contains multiple O(N)
1065 // operations. crbug.com/577989. 1056 // operations. crbug.com/577989.
1066 void HTMLSelectElement::selectOption(HTMLOptionElement* element, int optionIndex , SelectOptionFlags flags) 1057 void HTMLSelectElement::selectOption(HTMLOptionElement* element, SelectOptionFla gs flags)
1067 { 1058 {
1068 TRACE_EVENT0("blink", "HTMLSelectElement::selectOption"); 1059 TRACE_EVENT0("blink", "HTMLSelectElement::selectOption");
1069 ASSERT((!element && optionIndex < 0) || (element && optionIndex >= 0));
1070 1060
1071 // selectedIndex() is O(N). 1061 // selectedOption() is O(N).
1072 if (isAutofilled() && selectedIndex() != optionIndex) 1062 if (isAutofilled() && selectedOption() != element)
1073 setAutofilled(false); 1063 setAutofilled(false);
1074 1064
1075 if (element) { 1065 if (element) {
1076 element->setSelectedState(true); 1066 element->setSelectedState(true);
1077 if (flags & MakeOptionDirty) 1067 if (flags & MakeOptionDirty)
1078 element->setDirty(true); 1068 element->setDirty(true);
1079 } 1069 }
1080 1070
1081 // deselectItemsWithoutValidation() is O(N). 1071 // deselectItemsWithoutValidation() is O(N).
1082 if (flags & DeselectOtherOptions) 1072 if (flags & DeselectOtherOptions)
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
1279 } 1269 }
1280 } 1270 }
1281 } 1271 }
1282 1272
1283 setNeedsValidityCheck(); 1273 setNeedsValidityCheck();
1284 } 1274 }
1285 1275
1286 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) 1276 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value)
1287 { 1277 {
1288 bool oldMultiple = m_multiple; 1278 bool oldMultiple = m_multiple;
1289 int oldSelectedIndex = selectedIndex(); 1279 HTMLOptionElement* oldSelectedOption = selectedOption();
1290 m_multiple = !value.isNull(); 1280 m_multiple = !value.isNull();
1291 setNeedsValidityCheck(); 1281 setNeedsValidityCheck();
1292 lazyReattachIfAttached(); 1282 lazyReattachIfAttached();
1293 // Restore selectedIndex after changing the multiple flag to preserve 1283 // Restore selectedIndex after changing the multiple flag to preserve
1294 // selection as single-line and multi-line has different defaults. 1284 // selection as single-line and multi-line has different defaults.
1295 if (oldMultiple != m_multiple) { 1285 if (oldMultiple != m_multiple) {
1296 // Preserving the first selection is compatible with Firefox and 1286 // Preserving the first selection is compatible with Firefox and
1297 // WebKit. However Edge seems to "ask for a reset" simply. As of 2016 1287 // WebKit. However Edge seems to "ask for a reset" simply. As of 2016
1298 // March, the HTML specification says nothing about this. 1288 // March, the HTML specification says nothing about this.
1299 if (oldSelectedIndex >= 0) 1289 if (oldSelectedOption)
1300 selectOption(oldSelectedIndex, DeselectOtherOptions); 1290 selectOption(oldSelectedOption, DeselectOtherOptions);
1301 else 1291 else
1302 resetToDefaultSelection(); 1292 resetToDefaultSelection();
1303 } 1293 }
1304 } 1294 }
1305 1295
1306 void HTMLSelectElement::appendToFormData(FormData& formData) 1296 void HTMLSelectElement::appendToFormData(FormData& formData)
1307 { 1297 {
1308 const AtomicString& name = this->name(); 1298 const AtomicString& name = this->name();
1309 if (name.isEmpty()) 1299 if (name.isEmpty())
1310 return; 1300 return;
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after
1793 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDisabl edFormControl()) 1783 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDisabl edFormControl())
1794 return String(); 1784 return String();
1795 return toHTMLOptionElement(element)->displayLabel(); 1785 return toHTMLOptionElement(element)->displayLabel();
1796 } 1786 }
1797 1787
1798 void HTMLSelectElement::typeAheadFind(KeyboardEvent* event) 1788 void HTMLSelectElement::typeAheadFind(KeyboardEvent* event)
1799 { 1789 {
1800 int index = m_typeAhead.handleEvent(event, TypeAhead::MatchPrefix | TypeAhea d::CycleFirstChar); 1790 int index = m_typeAhead.handleEvent(event, TypeAhead::MatchPrefix | TypeAhea d::CycleFirstChar);
1801 if (index < 0) 1791 if (index < 0)
1802 return; 1792 return;
1803 selectOption(listToOptionIndex(index), DeselectOtherOptions | MakeOptionDirt y | DispatchInputAndChangeEvent); 1793 HTMLOptionElement* option = nullptr;
1794 if (static_cast<size_t>(index) < listItems().size() && isHTMLOptionElement(l istItems()[index]))
1795 option = toHTMLOptionElement(listItems()[index]);
1796 selectOption(option, DeselectOtherOptions | MakeOptionDirty | DispatchInputA ndChangeEvent);
1804 if (!usesMenuList()) 1797 if (!usesMenuList())
1805 listBoxOnChange(); 1798 listBoxOnChange();
1806 } 1799 }
1807 1800
1808 void HTMLSelectElement::accessKeySetSelectedIndex(int index) 1801 void HTMLSelectElement::accessKeySetSelectedIndex(int index)
1809 { 1802 {
1810 // First bring into focus the list box. 1803 // First bring into focus the list box.
1811 if (!focused()) 1804 if (!focused())
1812 accessKeyAction(false); 1805 accessKeyAction(false);
1813 1806
1814 const ListItems& items = listItems(); 1807 HTMLOptionElement* option = item(index);
1815 int listIndex = optionToListIndex(index); 1808 if (!option)
1816 if (listIndex < 0)
1817 return;
1818 HTMLElement& element = *items[listIndex];
1819 if (!isHTMLOptionElement(element))
1820 return; 1809 return;
1821 EventQueueScope scope; 1810 EventQueueScope scope;
1822 // If this index is already selected, unselect. otherwise update the 1811 // If this index is already selected, unselect. otherwise update the
1823 // selected index. 1812 // selected index.
1824 SelectOptionFlags flags = DispatchInputAndChangeEvent | (multiple() ? 0 : De selectOtherOptions); 1813 SelectOptionFlags flags = DispatchInputAndChangeEvent | (multiple() ? 0 : De selectOtherOptions);
1825 if (toHTMLOptionElement(element).selected()) { 1814 if (option->selected()) {
1826 if (usesMenuList()) 1815 if (usesMenuList())
1827 selectOption(-1, flags); 1816 selectOption(nullptr, flags);
1828 else 1817 else
1829 toHTMLOptionElement(element).setSelectedState(false); 1818 option->setSelectedState(false);
1830 } else { 1819 } else {
1831 selectOption(index, flags); 1820 selectOption(option, flags);
1832 } 1821 }
1833 toHTMLOptionElement(element).setDirty(true); 1822 option->setDirty(true);
1834 if (usesMenuList()) 1823 if (usesMenuList())
1835 return; 1824 return;
1836 listBoxOnChange(); 1825 listBoxOnChange();
1837 scrollToSelection(); 1826 scrollToSelection();
1838 } 1827 }
1839 1828
1840 unsigned HTMLSelectElement::length() const 1829 unsigned HTMLSelectElement::length() const
1841 { 1830 {
1842 unsigned options = 0; 1831 unsigned options = 0;
1843 for (auto& item : listItems()) { 1832 for (auto& item : listItems()) {
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after
2138 } 2127 }
2139 2128
2140 void HTMLSelectElement::didMutateSubtree() 2129 void HTMLSelectElement::didMutateSubtree()
2141 { 2130 {
2142 DCHECK(popupIsVisible()); 2131 DCHECK(popupIsVisible());
2143 DCHECK(m_popup); 2132 DCHECK(m_popup);
2144 m_popup->updateFromElement(PopupMenu::ByDOMChange); 2133 m_popup->updateFromElement(PopupMenu::ByDOMChange);
2145 } 2134 }
2146 2135
2147 } // namespace blink 2136 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLSelectElement.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698