HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const { ContainerNode* select = parentNode(); while (select && !select->hasTagName(selectTag)) select = select->parentNode(); if (!select) return 0; return toHTMLSelectElement(select); }
TEST_F(HTMLSelectElementTest, ActiveSelectionEndAfterOptionRemoval) { document().documentElement()->setInnerHTML("<select><optgroup><option selected>o1</option></optgroup></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); HTMLOptionElement* option = toHTMLOptionElement(select->firstChild()->firstChild()); EXPECT_EQ(1, select->activeSelectionEndListIndex()); select->firstChild()->removeChild(option, ASSERT_NO_EXCEPTION); EXPECT_EQ(-1, select->activeSelectionEndListIndex()); select->appendChild(option, ASSERT_NO_EXCEPTION); EXPECT_EQ(1, select->activeSelectionEndListIndex()); }
TEST_F(HTMLSelectElementTest, PopupIsVisible) { document().documentElement()->setInnerHTML("<select><option>o1</option></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); ASSERT(select); EXPECT_FALSE(select->popupIsVisible()); select->showPopup(); EXPECT_TRUE(select->popupIsVisible()); document().detach(); EXPECT_FALSE(select->popupIsVisible()); }
TEST_F(HTMLSelectElementTest, VisibleBoundsInVisualViewport) { document().documentElement()->setInnerHTML( "<select style='position:fixed; top:12.3px; height:24px; " "-webkit-appearance:none;'><option>o1</select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); ASSERT_NE(select, nullptr); IntRect bounds = select->visibleBoundsInVisualViewport(); EXPECT_EQ(24, bounds.height()); }
TEST_F(HTMLSelectElementTest, PreviousSelectableOption) { { document().documentElement()->setInnerHTML("<select></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); EXPECT_EQ(nullptr, select->previousSelectableOption(nullptr)); } { document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); EXPECT_EQ("o2", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr)); } { document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2 disabled></option></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); EXPECT_EQ("o1", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr)); } { document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2 style='display:none'></option></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); EXPECT_EQ("o1", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr)); } { document().documentElement()->setInnerHTML("<select><optgroup><option id=o1></option><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); EXPECT_EQ("o2", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr)); } { document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); HTMLOptionElement* option = toHTMLOptionElement(document().getElementById("o2")); EXPECT_EQ("o1", select->previousSelectableOption(option)->fastGetAttribute(HTMLNames::idAttr)); EXPECT_EQ(nullptr, select->previousSelectableOption(toHTMLOptionElement(document().getElementById("o1")))); } { document().documentElement()->setInnerHTML("<select><option id=o1></option><optgroup><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); HTMLOptionElement* option = toHTMLOptionElement(document().getElementById("o2")); EXPECT_EQ("o1", select->previousSelectableOption(option)->fastGetAttribute(HTMLNames::idAttr)); } }
TEST_F(HTMLSelectElementTest, DefaultToolTip) { document().documentElement()->setInnerHTML( "<select size=4><option value=" ">Placeholder</option><optgroup><option>o2</option></optgroup></select>", ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild()); Element* option = toElement(select->firstChild()); Element* optgroup = toElement(option->nextSibling()); EXPECT_EQ(String(), select->defaultToolTip()) << "defaultToolTip for SELECT without FORM and without required " "attribute should return null string."; EXPECT_EQ(select->defaultToolTip(), option->defaultToolTip()); EXPECT_EQ(select->defaultToolTip(), optgroup->defaultToolTip()); select->setBooleanAttribute(HTMLNames::requiredAttr, true); EXPECT_EQ("<<ValidationValueMissingForSelect>>", select->defaultToolTip()) << "defaultToolTip for SELECT without FORM and with required attribute " "should return a valueMissing message."; EXPECT_EQ(select->defaultToolTip(), option->defaultToolTip()); EXPECT_EQ(select->defaultToolTip(), optgroup->defaultToolTip()); HTMLFormElement* form = HTMLFormElement::create(document()); document().body()->appendChild(form); form->appendChild(select); EXPECT_EQ("<<ValidationValueMissingForSelect>>", select->defaultToolTip()) << "defaultToolTip for SELECT with FORM and required attribute should " "return a valueMissing message."; EXPECT_EQ(select->defaultToolTip(), option->defaultToolTip()); EXPECT_EQ(select->defaultToolTip(), optgroup->defaultToolTip()); form->setBooleanAttribute(HTMLNames::novalidateAttr, true); EXPECT_EQ(String(), select->defaultToolTip()) << "defaultToolTip for SELECT with FORM[novalidate] and required " "attribute should return null string."; EXPECT_EQ(select->defaultToolTip(), option->defaultToolTip()); EXPECT_EQ(select->defaultToolTip(), optgroup->defaultToolTip()); option->remove(); optgroup->remove(); EXPECT_EQ(String(), option->defaultToolTip()); EXPECT_EQ(String(), optgroup->defaultToolTip()); }
TEST_F(ExternalPopupMenuTest, DidAcceptIndex) { registerMockedURLLoad("select.html"); loadFrame("select.html"); HTMLSelectElement* select = toHTMLSelectElement(mainFrame()->frame()->document()->getElementById("select")); LayoutMenuList* menuList = toLayoutMenuList(select->layoutObject()); ASSERT_TRUE(menuList); select->showPopup(); ASSERT_TRUE(select->popupIsVisible()); WebExternalPopupMenuClient* client = static_cast<ExternalPopupMenu*>(select->popup()); client->didAcceptIndex(2); EXPECT_FALSE(select->popupIsVisible()); ASSERT_STREQ("2", menuList->text().utf8().data()); EXPECT_EQ(2, select->selectedIndex()); }
TEST_F(ExternalPopupMenuTest, DidAcceptIndicesClearSelect) { registerMockedURLLoad("select.html"); loadFrame("select.html"); HTMLSelectElement* select = toHTMLSelectElement(mainFrame()->frame()->document()->getElementById("select")); LayoutMenuList* menuList = toLayoutMenuList(select->layoutObject()); ASSERT_TRUE(menuList); select->showPopup(); ASSERT_TRUE(select->popupIsVisible()); WebExternalPopupMenuClient* client = static_cast<ExternalPopupMenu*>(select->popup()); WebVector<int> indices; client->didAcceptIndices(indices); EXPECT_FALSE(select->popupIsVisible()); EXPECT_EQ(-1, select->selectedIndex()); }
void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, int index, ExceptionState& exceptionState) { HTMLOptionElement* newOption = element.get(); if (!newOption) { exceptionState.throwTypeError("The element provided was not an HTMLOptionElement."); return; } if (index < -1) { exceptionState.throwDOMException(IndexSizeError, "The index provided (" + String::number(index) + ") is less than -1."); return; } HTMLSelectElement* select = toHTMLSelectElement(ownerNode()); if (index == -1 || unsigned(index) >= length()) select->add(newOption, 0, exceptionState); else select->add(newOption, toHTMLOptionElement(item(index)), exceptionState); ASSERT(!exceptionState.hadException()); }
void HTMLOptionsCollection::add(PassRefPtr<HTMLOptionElement> element, int index, ExceptionCode &ec) { HTMLOptionElement* newOption = element.get(); if (!newOption) { ec = TYPE_MISMATCH_ERR; return; } if (index < -1) { ec = INDEX_SIZE_ERR; return; } ec = 0; HTMLSelectElement* select = toHTMLSelectElement(base()); if (index == -1 || unsigned(index) >= length()) select->add(newOption, 0, ec); else select->add(newOption, static_cast<HTMLOptionElement*>(item(index)), ec); ASSERT(ec == 0); }
TEST_F(HTMLSelectElementTest, SaveRestoreSelectMultipleFormControlState) { document().documentElement()->setInnerHTML( String("<!DOCTYPE HTML><select id='sel' multiple>" "<option value='111' id='0'>111</option>" "<option value='222'>222</option>" "<option value='111' selected id='2'>!666</option>" "<option value='999' selected id='3'>999</option></select>"), ASSERT_NO_EXCEPTION); document().view()->updateAllLifecyclePhases(); HTMLFormControlElementWithState* select = toHTMLSelectElement(document().getElementById("sel")); HTMLOptionElement* opt0 = toHTMLOptionElement(document().getElementById("0")); HTMLOptionElement* opt2 = toHTMLOptionElement(document().getElementById("2")); HTMLOptionElement* opt3 = toHTMLOptionElement(document().getElementById("3")); // Save the select element state, and then restore again. // Test passes if the selected options are not changed. EXPECT_FALSE(opt0->selected()); EXPECT_TRUE(opt2->selected()); EXPECT_TRUE(opt3->selected()); FormControlState selectState = select->saveFormControlState(); EXPECT_EQ(4U, selectState.valueSize()); // Clear the selected state, to be restored by restoreFormControlState. opt2->setSelected(false); opt3->setSelected(false); ASSERT_FALSE(opt2->selected()); ASSERT_FALSE(opt3->selected()); // Restore select->restoreFormControlState(selectState); EXPECT_FALSE(opt0->selected()); EXPECT_TRUE(opt2->selected()); EXPECT_TRUE(opt3->selected()); }
int HTMLOptionsCollection::selectedIndex() const { return toHTMLSelectElement(ownerNode())->selectedIndex(); }
void HTMLOptionsCollection::setSelectedIndex(int index) { toHTMLSelectElement(ownerNode())->setSelectedIndex(index); }
inline HTMLSelectElement* LayoutListBox::selectElement() const { return toHTMLSelectElement(node()); }
void HTMLOptionsCollection::remove(int index) { toHTMLSelectElement(ownerNode())->remove(index); }
void JSHTMLOptionsCollection::indexSetter(ExecState* exec, unsigned index, JSValue value) { HTMLOptionsCollection* imp = static_cast<HTMLOptionsCollection*>(impl()); HTMLSelectElement* base = toHTMLSelectElement(imp->ownerNode()); selectIndexSetter(base, exec, index, value); }
bool HTMLOptionsCollection::anonymousIndexedSetterRemove(unsigned index, ExceptionState& exceptionState) { HTMLSelectElement* base = toHTMLSelectElement(ownerNode()); base->remove(index); return true; }
void HTMLOptionsCollection::add(const HTMLOptionElementOrHTMLOptGroupElement& element, const HTMLElementOrLong& before, ExceptionState& exceptionState) { toHTMLSelectElement(ownerNode()).add(element, before, exceptionState); }
void V8HTMLOptionsCollection::removeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) { HTMLOptionsCollection* imp = V8HTMLOptionsCollection::toNative(args.Holder()); HTMLSelectElement* base = toHTMLSelectElement(imp->ownerNode()); removeElement(base, args); }
void HTMLOptionsCollection::setLength(unsigned length, ExceptionCode& ec) { toHTMLSelectElement(base())->setLength(length, ec); }
WebSelectElement::operator HTMLSelectElement*() const { return toHTMLSelectElement(m_private.get()); }
WebSelectElement::operator PassRefPtrWillBeRawPtr<HTMLSelectElement>() const { return toHTMLSelectElement(m_private.get()); }
void HTMLOptionsCollection::setLength(unsigned length, ExceptionState& exceptionState) { toHTMLSelectElement(ownerNode())->setLength(length, exceptionState); }
HTMLSelectElement* LayoutMenuList::selectElement() const { return toHTMLSelectElement(node()); }
bool RenderThemeQtMobile::checkMultiple(RenderObject* o) const { HTMLSelectElement* select = o ? toHTMLSelectElement(o->node()) : 0; return select ? select->multiple() : false; }
static void notifyChildrenSelectionChange(AccessibilityObject* object) { // This static variables are needed to keep track of the old // focused object and its associated list object, as per previous // calls to this function, in order to properly decide whether to // emit some signals or not. static NeverDestroyed<RefPtr<AccessibilityObject>> oldListObject; static NeverDestroyed<RefPtr<AccessibilityObject>> oldFocusedObject; // Only list boxes and menu lists supported so far. if (!object || !(object->isListBox() || object->isMenuList())) return; // Only support HTML select elements so far (ARIA selectors not supported). Node* node = object->node(); if (!node || !isHTMLSelectElement(node)) return; // Emit signal from the listbox's point of view first. g_signal_emit_by_name(object->wrapper(), "selection-changed"); // Find the item where the selection change was triggered from. HTMLSelectElement* select = toHTMLSelectElement(node); if (!select) return; int changedItemIndex = select->activeSelectionStartListIndex(); AccessibilityObject* listObject = getListObject(object); if (!listObject) { oldListObject.get() = 0; return; } const AccessibilityObject::AccessibilityChildrenVector& items = listObject->children(); if (changedItemIndex < 0 || changedItemIndex >= static_cast<int>(items.size())) return; AccessibilityObject* item = items.at(changedItemIndex).get(); // Ensure the current list object is the same than the old one so // further comparisons make sense. Otherwise, just reset // oldFocusedObject so it won't be taken into account. if (oldListObject.get() != listObject) oldFocusedObject.get() = 0; AtkObject* axItem = item ? item->wrapper() : 0; AtkObject* axOldFocusedObject = oldFocusedObject.get() ? oldFocusedObject.get()->wrapper() : 0; // Old focused object just lost focus, so emit the events. if (axOldFocusedObject && axItem != axOldFocusedObject) { g_signal_emit_by_name(axOldFocusedObject, "focus-event", false); atk_object_notify_state_change(axOldFocusedObject, ATK_STATE_FOCUSED, false); } // Emit needed events for the currently (un)selected item. if (axItem) { bool isSelected = item->isSelected(); atk_object_notify_state_change(axItem, ATK_STATE_SELECTED, isSelected); g_signal_emit_by_name(axItem, "focus-event", isSelected); atk_object_notify_state_change(axItem, ATK_STATE_FOCUSED, isSelected); } // Update pointers to the previously involved objects. oldListObject.get() = listObject; oldFocusedObject.get() = item; }