예제 #1
0
void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
{
    m_listItems.clear();
    HTMLOptionElement* foundSelected = 0;
    for (Node* current = firstChild(); current; current = current->traverseNextSibling(this)) {
        if (current->hasTagName(optgroupTag) && current->firstChild()) {
            // FIXME: It doesn't make sense to add an optgroup to the list items,
            // when it has children, but not to add it if it happens to have,
            // children (say some comment nodes or text nodes), yet that's what
            // this code does!
            m_listItems.append(static_cast<HTMLElement*>(current));
            current = current->firstChild();
            // FIXME: It doesn't make sense to handle an <optgroup> inside another <optgroup>
            // if it's not the first child, but not handle it if it happens to be the first
            // child, yet that's what this code does!
        }

        if (current->hasTagName(optionTag)) {
            m_listItems.append(static_cast<HTMLElement*>(current));
            if (updateSelectedStates) {
                if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) {
                    foundSelected = static_cast<HTMLOptionElement*>(current);
                    foundSelected->setSelectedState(true);
                } else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) {
                    foundSelected->setSelectedState(false);
                    foundSelected = static_cast<HTMLOptionElement*>(current);
                }
            }
        }
        if (current->hasTagName(hrTag))
            m_listItems.append(static_cast<HTMLElement*>(current));
    }
    m_recalcListItems = false;
}
예제 #2
0
void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
{
    ASSERT(renderer() && renderer()->isListBox());
    
    unsigned start;
    unsigned end;
    ASSERT(m_activeSelectionAnchorIndex >= 0);
    start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
    end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);

    const Vector<HTMLElement*>& items = listItems();
    for (unsigned i = 0; i < items.size(); i++) {
        if (items[i]->hasLocalName(optionTag)) {
            HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
            if (!option->disabled()) {
                if (i >= start && i <= end)
                    option->setSelectedState(m_activeSelectionState);
                else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.size())
                    option->setSelectedState(false);
                else
                    option->setSelectedState(m_cachedStateForActiveSelection[i]);
            }
        }
    }

    scrollToSelection();
}
예제 #3
0
void SelectPopupClient::setValueAndClosePopup(int, const String& stringValue)
{
    ASSERT(m_element);

    static const char* cancelValue = "-1";
    if (stringValue == cancelValue) {
        closePopup();
        return;
    }

    if (m_size > 0) {
        bool selecteds[m_size];
        for (unsigned i = 0; i < m_size; i++)
            selecteds[i] = stringValue[i] - '0';

        const Vector<HTMLElement*>& items = m_element->listItems();

        if (items.size() != static_cast<unsigned int>(m_size))
            return;

        HTMLOptionElement* option;
        for (unsigned i = 0; i < m_size; i++) {
            if (items[i]->hasTagName(HTMLNames::optionTag)) {
                option = static_cast<HTMLOptionElement*>(items[i]);
                option->setSelectedState(selecteds[i]);
            }
        }
    }
    // Force repaint because we do not send mouse events to the select element
    // and the element doesn't automatically repaint itself.
    if (m_element->renderer())
        m_element->renderer()->repaint();

    m_notifyChangeTimer.startOneShot(0);
}
예제 #4
0
void SelectPopupClient::setValueAndClosePopup(int, const String& stringValue)
{

    ASSERT(m_size == stringValue.length());

    if (m_size > 0) {
        bool selecteds[m_size];
        for (unsigned i = 0; i < m_size; i++)
            selecteds[i] = stringValue[i] - '0';

        const WTF::Vector<HTMLElement*>& items = m_element->listItems();

        if (items.size() != static_cast<unsigned int>(m_size))
            return;

        HTMLOptionElement* option;
        for (unsigned i = 0; i < m_size; i++) {
            if (items[i]->hasTagName(HTMLNames::optionTag)) {
                option = static_cast<HTMLOptionElement*>(items[i]);
                option->setSelectedState(selecteds[i]);
            }
        }
    }
    // Force repaint because we do not send mouse events to the select element
    // and the element doesn't automatically repaint itself.
    m_element->dispatchFormControlChangeEvent();
    m_element->renderer()->repaint();
    closePopup();
}
예제 #5
0
void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChange)
{
    const Vector<HTMLElement*>& items = listItems();
    int listIndex = optionToListIndex(optionIndex);
    HTMLOptionElement* element = 0;

    if (!multiple())
        deselect = true;

    if (listIndex >= 0) {
        if (m_activeSelectionAnchorIndex < 0 || deselect)
            setActiveSelectionAnchorIndex(listIndex);
        if (m_activeSelectionEndIndex < 0 || deselect)
            setActiveSelectionEndIndex(listIndex);
        element = static_cast<HTMLOptionElement*>(items[listIndex]);
        element->setSelectedState(true);
    }

    if (deselect)
        deselectItems(element);

    scrollToSelection();

    // This only gets called with fireOnChange for menu lists. 
    if (fireOnChange && usesMenuList())
        menuListOnChange();

    Frame* frame = document()->frame();
    if (frame)
        frame->page()->chrome()->client()->formStateDidChange(this);
}
예제 #6
0
void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
{
    const Vector<HTMLElement*>& items = listItems();
    unsigned i;
    for (i = 0; i < items.size(); i++) {
        if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) {
            HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]);
            element->setSelectedState(false);
        }
    }
}
예제 #7
0
void HTMLSelectElement::reset()
{
    bool optionSelected = false;
    HTMLOptionElement* firstOption = 0;
    const Vector<HTMLElement*>& items = listItems();
    unsigned i;
    for (i = 0; i < items.size(); i++) {
        if (items[i]->hasLocalName(optionTag)) {
            HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[i]);
            if (!option->getAttribute(selectedAttr).isNull()) {
                option->setSelectedState(true);
                optionSelected = true;
            } else
                option->setSelectedState(false);
            if (!firstOption)
                firstOption = option;
        }
    }
    if (!optionSelected && firstOption && usesMenuList())
        firstOption->setSelectedState(true);
    
    setChanged();
}
예제 #8
0
void HTMLSelectElement::accessKeySetSelectedIndex(int index)
{    
    // first bring into focus the list box
    if (!focused())
        accessKeyAction(false);
    
    // if this index is already selected, unselect. otherwise update the selected index
    Node* listNode = item(index);
    if (listNode && listNode->hasTagName(optionTag)) {
        HTMLOptionElement* listElement = static_cast<HTMLOptionElement*>(listNode);
        if (listElement->selected())
            listElement->setSelectedState(false);
        else
            setSelectedIndex(index, false, true);
    }
    
    listBoxOnChange();
    scrollToSelection();
}
예제 #9
0
void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
{
    if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) {
        focus();
        
        MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
        int listIndex = static_cast<RenderListBox*>(renderer())->listIndexAtOffset(mEvt->offsetX(), mEvt->offsetY());
        if (listIndex >= 0) {
            // Save the selection so it can be compared to the new selection when we call onChange during mouseup, or after autoscroll finishes.
            saveLastSelection();

            m_activeSelectionState = true;
            
            bool multiSelectKeyPressed = false;
#if PLATFORM(MAC)
            multiSelectKeyPressed = mEvt->metaKey();
#else
            multiSelectKeyPressed = mEvt->ctrlKey();
#endif

            bool shiftSelect = multiple() && mEvt->shiftKey();
            bool multiSelect = multiple() && multiSelectKeyPressed && !mEvt->shiftKey();
            
            HTMLElement* clickedElement = listItems()[listIndex];            
            HTMLOptionElement* option = 0;
            if (clickedElement->hasLocalName(optionTag)) {
                option = static_cast<HTMLOptionElement*>(clickedElement);
                
                // Keep track of whether an active selection (like during drag selection), should select or deselect
                if (option->selected() && multiSelectKeyPressed)
                    m_activeSelectionState = false;

                if (!m_activeSelectionState)
                    option->setSelectedState(false);
            }
            
            // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option.
            // If no option was clicked, then this will deselect all items in the list.
            if (!shiftSelect && !multiSelect)
                deselectItems(option);

            // If the anchor hasn't been set, and we're doing a single selection or a shift selection, then initialize the anchor to the first selected index.
            if (m_activeSelectionAnchorIndex < 0 && !multiSelect)
                setActiveSelectionAnchorIndex(selectedIndex());

            // Set the selection state of the clicked option
            if (option && !option->disabled())
                option->setSelectedState(true);
            
            // If there was no selectedIndex() for the previous initialization, or
            // If we're doing a single selection, or a multiple selection (using cmd or ctrl), then initialize the anchor index to the listIndex that just got clicked.
            if (listIndex >= 0 && (m_activeSelectionAnchorIndex < 0 || !shiftSelect))
                setActiveSelectionAnchorIndex(listIndex);
            
            setActiveSelectionEndIndex(listIndex);
            updateListBoxSelection(!multiSelect);

            if (Frame* frame = document()->frame())
                frame->eventHandler()->setMouseDownMayStartAutoscroll();

            evt->setDefaultHandled();
        }
    } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton && document()->frame()->eventHandler()->autoscrollRenderer() != renderer())
        // This makes sure we fire onChange for a single click.  For drag selection, onChange will fire when the autoscroll timer stops.
        listBoxOnChange();
    else if (evt->type() == eventNames().keydownEvent) {
        if (!evt->isKeyboardEvent())
            return;
        String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier();

        int endIndex = 0;        
        if (m_activeSelectionEndIndex < 0) {
            // Initialize the end index
            if (keyIdentifier == "Down")
                endIndex = nextSelectableListIndex(lastSelectedListIndex());
            else if (keyIdentifier == "Up")
                endIndex = previousSelectableListIndex(optionToListIndex(selectedIndex()));
        } else {
            // Set the end index based on the current end index
            if (keyIdentifier == "Down")
                endIndex = nextSelectableListIndex(m_activeSelectionEndIndex);
            else if (keyIdentifier == "Up")
                endIndex = previousSelectableListIndex(m_activeSelectionEndIndex);    
        }
        
        if (keyIdentifier == "Down" || keyIdentifier == "Up") {
            // Save the selection so it can be compared to the new selection when we call onChange immediately after making the new selection.
            saveLastSelection();

            ASSERT(endIndex >= 0 && (unsigned)endIndex < listItems().size()); 
            setActiveSelectionEndIndex(endIndex);
            
            // If the anchor is unitialized, or if we're going to deselect all other options, then set the anchor index equal to the end index.
            bool deselectOthers = !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey();
            if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
                m_activeSelectionState = true;
                if (deselectOthers)
                    deselectItems();
                setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
            }

            static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(endIndex);
            updateListBoxSelection(deselectOthers);
            listBoxOnChange();
            evt->setDefaultHandled();
        }
    } else if (evt->type() == eventNames().keypressEvent) {
        if (!evt->isKeyboardEvent())
            return;
        int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode();

        if (keyCode == '\r') {
            if (form())
                form()->submitClick(evt);
            evt->setDefaultHandled();
            return;
        }
    }
}