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());
}
Exemple #9
0
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());
}
Exemple #12
0
int HTMLOptionsCollection::selectedIndex() const
{
    return toHTMLSelectElement(ownerNode())->selectedIndex();
}
Exemple #13
0
void HTMLOptionsCollection::setSelectedIndex(int index)
{
    toHTMLSelectElement(ownerNode())->setSelectedIndex(index);
}
Exemple #14
0
inline HTMLSelectElement* LayoutListBox::selectElement() const {
  return toHTMLSelectElement(node());
}
Exemple #15
0
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);
}
Exemple #17
0
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);
}
Exemple #21
0
WebSelectElement::operator HTMLSelectElement*() const {
  return toHTMLSelectElement(m_private.get());
}
WebSelectElement::operator PassRefPtrWillBeRawPtr<HTMLSelectElement>() const
{
    return toHTMLSelectElement(m_private.get());
}
Exemple #23
0
void HTMLOptionsCollection::setLength(unsigned length, ExceptionState& exceptionState)
{
    toHTMLSelectElement(ownerNode())->setLength(length, exceptionState);
}
Exemple #24
0
HTMLSelectElement* LayoutMenuList::selectElement() const {
  return toHTMLSelectElement(node());
}
Exemple #25
0
bool RenderThemeQtMobile::checkMultiple(RenderObject* o) const
{
    HTMLSelectElement* select = o ? toHTMLSelectElement(o->node()) : 0;
    return select ? select->multiple() : false;
}
Exemple #26
0
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;
}