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

Unified Diff: third_party/WebKit/Source/core/html/HTMLSelectElement.cpp

Issue 1837463002: Improve conformance of default OPTION selection of SELECT element (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Renaming to resetToDefaultSelection Created 4 years, 9 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
« no previous file with comments | « third_party/WebKit/Source/core/html/HTMLSelectElement.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index 9c8658e2128d00dcb80e6ed67f6d4ce23aab0424..ba612d0c353f0e04e5568257887cd41a16d8d1f4 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -369,18 +369,12 @@ void HTMLSelectElement::parseAttribute(const QualifiedName& name, const AtomicSt
if (Attribute* sizeAttribute = ensureUniqueElementData().attributes().find(sizeAttr))
sizeAttribute->setValue(attrSize);
}
- size = std::max(size, 0u);
-
- // Ensure that we've determined selectedness of the items at least once
- // prior to changing the size.
- if (oldSize != size)
- updateListItemSelectedStates();
-
- m_size = size;
+ m_size = std::max(size, 0u);
setNeedsValidityCheck();
- if (m_size != oldSize && inActiveDocument()) {
- lazyReattachIfAttached();
- setRecalcListItems();
+ if (m_size != oldSize) {
+ if (inActiveDocument())
+ lazyReattachIfAttached();
+ resetToDefaultSelection();
}
} else if (name == multipleAttr) {
parseMultipleAttribute(value);
@@ -416,7 +410,6 @@ LayoutObject* HTMLSelectElement::createLayoutObject(const ComputedStyle&)
PassRefPtrWillBeRawPtr<HTMLCollection> HTMLSelectElement::selectedOptions()
{
- updateListItemSelectedStates();
return ensureCachedCollection<HTMLCollection>(SelectedOptions);
}
@@ -425,14 +418,6 @@ PassRefPtrWillBeRawPtr<HTMLOptionsCollection> HTMLSelectElement::options()
return ensureCachedCollection<HTMLOptionsCollection>(SelectOptions);
}
-void HTMLSelectElement::updateListItemSelectedStates()
-{
- if (!m_shouldRecalcListItems)
- return;
- recalcListItems();
- setNeedsValidityCheck();
-}
-
void HTMLSelectElement::childrenChanged(const ChildrenChange& change)
{
setRecalcListItems();
@@ -790,7 +775,7 @@ const HTMLSelectElement::ListItems& HTMLSelectElement::listItems() const
} else {
#if ENABLE(ASSERT)
WillBeHeapVector<RawPtrWillBeMember<HTMLElement>> items = m_listItems;
- recalcListItems(false);
+ recalcListItems();
ASSERT(items == m_listItems);
#endif
}
@@ -823,15 +808,13 @@ void HTMLSelectElement::setRecalcListItems()
}
}
-void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
+void HTMLSelectElement::recalcListItems() const
{
TRACE_EVENT0("blink", "HTMLSelectElement::recalcListItems");
m_listItems.clear();
m_shouldRecalcListItems = false;
- HTMLOptionElement* foundSelected = nullptr;
- HTMLOptionElement* firstOption = nullptr;
for (Element* currentElement = ElementTraversal::firstWithin(*this); currentElement && m_listItems.size() < maxListItems; ) {
if (!currentElement->isHTMLElement()) {
currentElement = ElementTraversal::nextSkippingChildren(*currentElement, this);
@@ -854,24 +837,9 @@ void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
}
}
- if (isHTMLOptionElement(current)) {
+ if (isHTMLOptionElement(current))
m_listItems.append(&current);
- if (updateSelectedStates && !m_multiple) {
- HTMLOptionElement& option = toHTMLOptionElement(current);
- if (!firstOption)
- firstOption = &option;
- if (option.selected()) {
- if (foundSelected)
- foundSelected->setSelectedState(false);
- foundSelected = &option;
- } else if (m_size <= 1 && !foundSelected && !option.isDisabledFormControl()) {
- foundSelected = &option;
- foundSelected->setSelectedState(true);
- }
- }
- }
-
if (isHTMLHRElement(current))
m_listItems.append(&current);
@@ -883,9 +851,46 @@ void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
// from the <select>'s subtree at this point.
currentElement = ElementTraversal::nextSkippingChildren(*currentElement, this);
}
+}
- if (!foundSelected && m_size <= 1 && firstOption && !firstOption->selected())
- firstOption->setSelectedState(true);
+void HTMLSelectElement::resetToDefaultSelection()
+{
+ // https://html.spec.whatwg.org/multipage/forms.html#ask-for-a-reset
+ if (multiple())
+ return;
+ HTMLOptionElement* firstEnabledOption = nullptr;
+ int firstEnabledOptionIndex = -1;
+ HTMLOptionElement* lastSelectedOption = nullptr;
+ bool didChange = false;
+ int optionIndex = 0;
+ // We can't use HTMLSelectElement::options here because this function is
+ // called in Node::insertedInto and Node::removedFrom before invalidating
+ // node collections.
+ for (auto& item : listItems()) {
+ if (!isHTMLOptionElement(item))
+ continue;
+ HTMLOptionElement* option = toHTMLOptionElement(item);
+ if (option->selected()) {
+ if (lastSelectedOption) {
+ lastSelectedOption->setSelectedState(false);
+ didChange = true;
+ }
+ lastSelectedOption = option;
+ }
+ if (!firstEnabledOption && !option->isDisabledFormControl()) {
+ firstEnabledOption = option;
+ firstEnabledOptionIndex = optionIndex;
+ }
+ ++optionIndex;
+ }
+ if (!lastSelectedOption && m_size <= 1 && firstEnabledOption && !firstEnabledOption->selected()) {
+ selectOption(firstEnabledOption, firstEnabledOptionIndex, 0);
+ lastSelectedOption = firstEnabledOption;
+ didChange = true;
+ }
+ if (didChange)
+ setNeedsValidityCheck();
+ m_lastOnChangeOption = lastSelectedOption;
}
HTMLOptionElement* HTMLSelectElement::selectedOption() const
@@ -980,13 +985,20 @@ void HTMLSelectElement::optionInserted(HTMLOptionElement& option, bool optionIsS
{
ASSERT(option.ownerSelectElement() == this);
setRecalcListItems();
- if (optionIsSelected)
+ if (optionIsSelected) {
selectOption(&option);
+ } else {
+ // No need to reset if we already have a selected option.
+ if (!m_lastOnChangeOption)
+ resetToDefaultSelection();
+ }
}
void HTMLSelectElement::optionRemoved(const HTMLOptionElement& option)
{
setRecalcListItems();
+ if (option.selected() || !m_lastOnChangeOption)
+ resetToDefaultSelection();
if (m_lastOnChangeOption == &option)
m_lastOnChangeOption.clear();
if (m_optionToScrollTo == &option)
@@ -1242,33 +1254,14 @@ void HTMLSelectElement::appendToFormData(FormData& formData)
void HTMLSelectElement::resetImpl()
{
- HTMLOptionElement* firstOption = nullptr;
- HTMLOptionElement* selectedOption = nullptr;
-
for (auto& item : listItems()) {
if (!isHTMLOptionElement(item))
continue;
HTMLOptionElement* option = toHTMLOptionElement(item);
- if (option->fastHasAttribute(selectedAttr)) {
- if (selectedOption && !m_multiple)
- selectedOption->setSelectedState(false);
- option->setSelectedState(true);
- selectedOption = option;
- } else {
- option->setSelectedState(false);
- }
+ option->setSelectedState(option->fastHasAttribute(selectedAttr));
option->setDirty(false);
-
- if (!firstOption && !option->isDisabledFormControl())
- firstOption = option;
- }
-
- if (!selectedOption && firstOption && !m_multiple && m_size <= 1) {
- firstOption->setSelectedState(true);
- selectedOption = firstOption;
}
-
- m_lastOnChangeOption = selectedOption;
+ resetToDefaultSelection();
setOptionsChangedOnLayoutObject();
setNeedsValidityCheck();
}
@@ -1794,7 +1787,6 @@ unsigned HTMLSelectElement::length() const
void HTMLSelectElement::finishParsingChildren()
{
HTMLFormControlElementWithState::finishParsingChildren();
- updateListItemSelectedStates();
if (usesMenuList())
return;
scrollToOption(selectedOption());
@@ -1840,16 +1832,6 @@ DEFINE_TRACE(HTMLSelectElement)
HTMLFormControlElementWithState::trace(visitor);
}
-void HTMLSelectElement::willRecalcStyle(StyleRecalcChange change)
-{
- // recalcListItems will update the selected state of the <option> elements
- // in this <select> so we need to do it before we recalc their style so they
- // match the right selectors (ex. :checked).
- // TODO(esprehn): Find a way to avoid needing a willRecalcStyle callback.
- if (m_shouldRecalcListItems)
- recalcListItems();
-}
-
void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root)
{
RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create(document());
« 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