Commit 31872c80 authored by adele's avatar adele

LayoutTests:

        Reviewed by Hyatt.

        Updated test for <rdar://problem/4990050> REGRESSION: onchange gets fired when clicking on a programmatically selected element in a listbox
        http://bugs.webkit.org/show_bug.cgi?id=12725

        * fast/forms/listbox-onchange-expected.txt:
        * fast/forms/listbox-onchange.html:

WebCore:

        Reviewed by Hyatt.

        Fix for <rdar://problem/4990050> REGRESSION: onchange gets fired when clicking on a programmatically selected element in a listbox
        http://bugs.webkit.org/show_bug.cgi?id=12725

        Test: updated fast/forms/listbox-onchange.html

        Added HTMLSelectElement::saveLastSelection that is called before changing a selection that could result
        in onChange being called.  m_lastOnChangeIndex and m_lastOnChangeSelection no longer have to be up-to date all the time, 
        they just have to be up-to-date before we execute an action that may trigger onChange.

        * html/HTMLOptionElement.cpp: (WebCore::HTMLOptionElement::setSelectedState): Added.
          The HTMLSelectElement will only set an option's selected state with this method.  This ensures
          that notifyOptionSelected won't get called when the call originates from the select element.
        * html/HTMLOptionElement.h:

        * html/HTMLSelectElement.cpp:
        (WebCore::HTMLSelectElement::deselectItems): Calls setSelectedState.
        (WebCore::HTMLSelectElement::setSelectedIndex): ditto. Don't update the last selection variables here.  Scroll to the new selection.
         The scrolling call used to only be in notifyOptionSelected.  There's no reason we shouldn't scroll when the selection is set through
         the HTMLSelectElement.
        (WebCore::HTMLSelectElement::setValue): Call setSelectedIndex to update all options selected state.
        (WebCore::HTMLSelectElement::restoreState): Call setSelectedState.
        (WebCore::HTMLSelectElement::selectAll): Call saveLastSelection before making the selection, and calling onChange.
        (WebCore::HTMLSelectElement::recalcListItems): Call setSelectedState.  Don't need to save selection here anymore, 
         since it will get saved before we call onChange.
        (WebCore::HTMLSelectElement::reset): ditto.
        (WebCore::HTMLSelectElement::dispatchFocusEvent): Added. Call saveLastSelection for menu lists, since onChange can be fired
         on blur.
        (WebCore::HTMLSelectElement::dispatchBlurEvent): Call menuListOnChange.
        (WebCore::HTMLSelectElement::menuListDefaultEventHandler): Call saveLastSelection before showing the popup window.
        (WebCore::HTMLSelectElement::listBoxDefaultEventHandler):  Call saveLastSelection during mousedown (to prepare for an 
         onchange during mouseup, or after autoscroll).
        (WebCore::HTMLSelectElement::updateListBoxSelection): Call setSelectedState.

        (WebCore::HTMLSelectElement::menuListOnChange): Added. Compares the m_lastOnChangeIndex to the selectedIndex().
        (WebCore::HTMLSelectElement::listBoxOnChange): Move the m_lastOnChangeSelection creation to saveLastSelection.
        (WebCore::HTMLSelectElement::saveLastSelection): Added. Sets m_lastOnChangeIndex or m_lastOnChangeSelection.
        * html/HTMLSelectElement.h:
        * platform/PopupMenu.h:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@20259 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 4eee8692
2007-03-16 Adele Peterson <adele@apple.com>
Reviewed by Hyatt.
Updated test for <rdar://problem/4990050> REGRESSION: onchange gets fired when clicking on a programmatically selected element in a listbox
http://bugs.webkit.org/show_bug.cgi?id=12725
* fast/forms/listbox-onchange-expected.txt:
* fast/forms/listbox-onchange.html:
2007-03-16 Oliver Hunt <oliver@apple.com>
Reviewed by Hyatt.
Results:
1) Make sure onChange fires when clicking
1) Make sure onChange doesn't fire when clicking on an initially selected item
2) Make sure onChange fires when deselecting an initially selected item
onChange fired
2) Make sure onChange doesn't fire when clicking again on the same item
3) Make sure onChange fires when clicking on a new item
3) Make sure onChange fires when clicking
onChange fired
4) Make sure onChange fires when changing the selection with the keyboard
4) Make sure onChange doesn't fire when clicking again on the same item
5) Make sure onChange fires when clicking on a new item
onChange fired
6) Make sure onChange fires when changing the selection with the keyboard
onChange fired
7) Make sure onChange doesn't fire when setting the select element's value from JS
8) Make sure onChange doesn't fire when clicking on the already selected option
9) Make sure onChange doesn't fire when setting an option's selected state from JS
10) Make sure onChange doesn't fire when clicking on this option
11) Make sure onChange fires when deselecting the last selected option with a mouse click
onChange fired
12) Make sure onChange doesn't fire when adding a new selected option
13) Make sure onChange doesn't fire when clicking on it
14) Make sure onChange fires when clicking on a previously selected option
onChange fired
15) Make sure onChange doesn't fire when removing a selected option
16) Make sure onChange doesn't fire when clicking on the option that remains selected
......@@ -7,6 +7,11 @@
results.appendChild(document.createTextNode("Results:"));
document.body.appendChild(results);
}
function checkSelection(expected) {
actual = getSelectedOptions("sl1");
if (actual.toString() != expected)
log('Incorrect selection: "' + actual + '" instead of "' + expected + '"');
}
function test() {
setup();
......@@ -14,36 +19,113 @@
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
log("1) Make sure onChange fires when clicking");
clickOnSelect("sl1", 2);
log("2) Make sure onChange doesn't fire when clicking again on the same item");
clickOnSelect("sl1", 2);
checkSelection("0");
log("3) Make sure onChange fires when clicking on a new item");
clickOnSelect("sl1", 0);
log("4) Make sure onChange fires when changing the selection with the keyboard");
log("1) Make sure onChange doesn't fire when clicking on an initially selected item");
mouseDownOnSelect("sl1", 0, false, false);
mouseUpOnSelect("sl1", 0, false, false);
checkSelection("0");
log("2) Make sure onChange fires when deselecting an initially selected item");
mouseDownOnSelect("sl1", 0, false, true);
mouseUpOnSelect("sl1", 0, false, true);
checkSelection("");
log("3) Make sure onChange fires when clicking");
mouseDownOnSelect("sl1", 2, false, false);
mouseUpOnSelect("sl1", 2, false, false);
checkSelection("2");
log("4) Make sure onChange doesn't fire when clicking again on the same item");
mouseDownOnSelect("sl1", 2, false, false);
mouseUpOnSelect("sl1", 2, false, false);
checkSelection("2");
log("5) Make sure onChange fires when clicking on a new item");
mouseDownOnSelect("sl1", 0, false, false);
mouseUpOnSelect("sl1", 0, false, false);
checkSelection("0");
log("6) Make sure onChange fires when changing the selection with the keyboard");
keyPressOnSelect("sl1", "Down", true, false);
checkSelection("0,1");
log("7) Make sure onChange doesn't fire when setting the select element's value from JS");
document.getElementById("sl1").value = "2";
checkSelection("2");
log("8) Make sure onChange doesn't fire when clicking on the already selected option");
mouseDownOnSelect("sl1", 2, false, false);
mouseUpOnSelect("sl1", 2, false, false);
checkSelection("2");
log("9) Make sure onChange doesn't fire when setting an option's selected state from JS");
document.getElementById("sl1").item(3).selected = true;
checkSelection("2,3");
document.getElementById("sl1").item(2).selected = false;
checkSelection("3");
log("10) Make sure onChange doesn't fire when clicking on this option");
mouseDownOnSelect("sl1", 3, false, false);
mouseUpOnSelect("sl1", 3, false, false);
checkSelection("3");
log("11) Make sure onChange fires when deselecting the last selected option with a mouse click");
mouseDownOnSelect("sl1", 3, false, true);
mouseUpOnSelect("sl1", 3, false, true);
checkSelection("");
log("12) Make sure onChange doesn't fire when adding a new selected option");
option = document.createElement("option");
option.setAttribute("selected", "");
option.appendChild(document.createTextNode("item 4"));
document.getElementById("sl1").appendChild(option);
checkSelection("4");
log("13) Make sure onChange doesn't fire when clicking on it");
mouseDownOnSelect("sl1", 4, false, false);
mouseUpOnSelect("sl1", 4, false, false);
checkSelection("4");
log("14) Make sure onChange fires when clicking on a previously selected option");
mouseDownOnSelect("sl1", 3, false, true);
mouseUpOnSelect("sl1", 3, false, true);
checkSelection("3,4");
log("15) Make sure onChange doesn't fire when removing a selected option");
document.getElementById("sl1").removeChild(document.getElementById("sl1").item(4));
checkSelection("3");
log("16) Make sure onChange doesn't fire when clicking on the option that remains selected");
mouseDownOnSelect("sl1", 3, false, false);
mouseUpOnSelect("sl1", 3, false, false);
checkSelection("3");
if (window.layoutTestController)
layoutTestController.notifyDone();
}
function clickOnSelect(selId, index) {
function mouseDownOnSelect(selId, index, shift, meta) {
var sl = document.getElementById(selId);
var itemHeight = 15;
var y = 10 + index * itemHeight;
if (window.layoutTestController) {
eventSender.mouseMoveTo(sl.offsetLeft + 10, sl.offsetTop + y);
eventSender.mouseDown();
eventSender.mouseUp();
}
var itemHeight = 14;
var border = 1;
var y = border + index * itemHeight - window.pageYOffset;
var event = document.createEvent("MouseEvent");
event.initMouseEvent("mousedown", true, true, document.defaultView, 1, sl.offsetLeft + border, sl.offsetTop + y, sl.offsetLeft + border, sl.offsetTop + y, false, false, shift, meta, 0, document);
sl.dispatchEvent(event);
}
function mouseUpOnSelect(selId, index, shift, meta) {
var sl = document.getElementById(selId);
var itemHeight = 14;
var border = 1;
var y = border + index * itemHeight - window.pageYOffset;
var event = document.createEvent("MouseEvent");
event.initMouseEvent("mouseup", true, true, document.defaultView, 1, sl.offsetLeft + border, sl.offsetTop + y, sl.offsetLeft + border, sl.offsetTop + y, false, false, shift, meta, 0, document);
sl.dispatchEvent(event);
}
function keyPressOnSelect(selId, identifier, shift, meta) {
var sl = document.getElementById(selId);
var event = document.createEvent("KeyboardEvents");
......@@ -51,6 +133,15 @@
sl.dispatchEvent(event);
}
function getSelectedOptions(selId) {
result = new Array;
var sl = document.getElementById(selId);
for (i = 0; i < sl.options.length; ++i)
if (sl.item(i).selected)
result.push(i);
return result;
}
function log(msg) {
var r = document.getElementById('res');
r.innerHTML = r.innerHTML + "<br>" + msg;
......@@ -59,10 +150,10 @@
</head>
<body onload="test()">
<select id="sl1" size=5 multiple onchange="log('onChange fired')">
<option>item 0
<option>item 1
<option>item 2
<option>item 3
<option selected value="0">item 0</option>
<option value="1">item 1
<option value="2">item 2
<option value="3">item 3
</select>
</body>
</html>
2007-03-17 Adele Peterson <adele@apple.com>
Reviewed by Hyatt.
Fix for <rdar://problem/4990050> REGRESSION: onchange gets fired when clicking on a programmatically selected element in a listbox
http://bugs.webkit.org/show_bug.cgi?id=12725
Test: updated fast/forms/listbox-onchange.html
Added HTMLSelectElement::saveLastSelection that is called before changing a selection that could result
in onChange being called. m_lastOnChangeIndex and m_lastOnChangeSelection no longer have to be up-to date all the time,
they just have to be up-to-date before we execute an action that may trigger onChange.
* html/HTMLOptionElement.cpp: (WebCore::HTMLOptionElement::setSelectedState): Added.
The HTMLSelectElement will only set an option's selected state with this method. This ensures
that notifyOptionSelected won't get called when the call originates from the select element.
* html/HTMLOptionElement.h:
* html/HTMLSelectElement.cpp:
(WebCore::HTMLSelectElement::deselectItems): Calls setSelectedState.
(WebCore::HTMLSelectElement::setSelectedIndex): ditto. Don't update the last selection variables here. Scroll to the new selection.
The scrolling call used to only be in notifyOptionSelected. There's no reason we shouldn't scroll when the selection is set through
the HTMLSelectElement.
(WebCore::HTMLSelectElement::setValue): Call setSelectedIndex to update all options selected state.
(WebCore::HTMLSelectElement::restoreState): Call setSelectedState.
(WebCore::HTMLSelectElement::selectAll): Call saveLastSelection before making the selection, and calling onChange.
(WebCore::HTMLSelectElement::recalcListItems): Call setSelectedState. Don't need to save selection here anymore,
since it will get saved before we call onChange.
(WebCore::HTMLSelectElement::reset): ditto.
(WebCore::HTMLSelectElement::dispatchFocusEvent): Added. Call saveLastSelection for menu lists, since onChange can be fired
on blur.
(WebCore::HTMLSelectElement::dispatchBlurEvent): Call menuListOnChange.
(WebCore::HTMLSelectElement::menuListDefaultEventHandler): Call saveLastSelection before showing the popup window.
(WebCore::HTMLSelectElement::listBoxDefaultEventHandler): Call saveLastSelection during mousedown (to prepare for an
onchange during mouseup, or after autoscroll).
(WebCore::HTMLSelectElement::updateListBoxSelection): Call setSelectedState.
(WebCore::HTMLSelectElement::menuListOnChange): Added. Compares the m_lastOnChangeIndex to the selectedIndex().
(WebCore::HTMLSelectElement::listBoxOnChange): Move the m_lastOnChangeSelection creation to saveLastSelection.
(WebCore::HTMLSelectElement::saveLastSelection): Added. Sets m_lastOnChangeIndex or m_lastOnChangeSelection.
* html/HTMLSelectElement.h:
* platform/PopupMenu.h:
2007-03-16 Oliver Hunt <oliver@apple.com>
Reviewed by Hyatt.
......
......@@ -175,7 +175,16 @@ void HTMLOptionElement::setSelected(bool selected)
return;
m_selected = selected;
if (HTMLSelectElement* select = getSelect())
select->notifyOptionSelected(this, selected);
select->setSelectedIndex(selected ? index() : -1, false);
}
void HTMLOptionElement::setSelectedState(bool selected)
{
if (m_selected == selected)
return;
m_selected = selected;
setChanged();
}
void HTMLOptionElement::childrenChanged()
......
......@@ -65,6 +65,7 @@ public:
bool selected() const { return m_selected; }
void setSelected(bool);
void setSelectedState(bool);
HTMLSelectElement* getSelect() const;
......
......@@ -163,8 +163,7 @@ void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement)
for (i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) {
HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]);
element->m_selected = false;
element->setChanged();
element->setSelectedState(false);
}
}
}
......@@ -175,25 +174,23 @@ void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fi
int listIndex = optionToListIndex(optionIndex);
HTMLOptionElement* element = 0;
// Make a local copy, since setSelected() can update m_lastOnChangeIndex.
int lastOnChangeIndex = m_lastOnChangeIndex;
if (listIndex >= 0) {
if (m_activeSelectionAnchorIndex < 0 || deselect)
setActiveSelectionAnchorIndex(listIndex);
if (m_activeSelectionEndIndex < 0 || deselect)
setActiveSelectionEndIndex(listIndex);
element = static_cast<HTMLOptionElement*>(items[listIndex]);
element->setSelected(true);
} else if (deselect)
m_lastOnChangeIndex = -1;
element->setSelectedState(true);
}
if (deselect)
deselectItems(element);
ASSERT(m_lastOnChangeIndex == -1 || m_lastOnChangeIndex == optionIndex);
if (fireOnChange && usesMenuList() && lastOnChangeIndex != optionIndex)
onChange();
scrollToSelection();
//ASSERT(m_lastOnChangeIndex == -1 || m_lastOnChangeIndex == optionIndex);
if (fireOnChange && usesMenuList())
menuListOnChange();
}
int HTMLSelectElement::activeSelectionStartListIndex() const
......@@ -265,10 +262,14 @@ void HTMLSelectElement::setValue(const String &value)
// find the option with value() matching the given parameter
// and make it the current selection.
const Vector<HTMLElement*>& items = listItems();
unsigned optionIndex = 0;
for (unsigned i = 0; i < items.size(); i++)
if (items[i]->hasLocalName(optionTag) && static_cast<HTMLOptionElement*>(items[i])->value() == value) {
static_cast<HTMLOptionElement*>(items[i])->setSelected(true);
return;
if (items[i]->hasLocalName(optionTag)) {
if (static_cast<HTMLOptionElement*>(items[i])->value() == value) {
setSelectedIndex(optionIndex, true);
return;
}
optionIndex++;
}
}
......@@ -288,12 +289,13 @@ String HTMLSelectElement::stateValue() const
void HTMLSelectElement::restoreState(const String& state)
{
recalcListItems();
const Vector<HTMLElement*>& items = listItems();
int l = items.size();
for (int i = 0; i < l; i++)
if (items[i]->hasLocalName(optionTag))
static_cast<HTMLOptionElement*>(items[i])->setSelected(state[i] == 'X');
static_cast<HTMLOptionElement*>(items[i])->setSelectedState(state[i] == 'X');
setChanged(true);
}
......@@ -402,6 +404,8 @@ void HTMLSelectElement::selectAll()
if (!renderer() || !multiple())
return;
saveLastSelection();
m_activeSelectionState = true;
setActiveSelectionAnchorIndex(nextSelectableListIndex(-1));
setActiveSelectionEndIndex(previousSelectableListIndex(-1));
......@@ -501,9 +505,9 @@ void HTMLSelectElement::recalcListItems() const
m_listItems.append(static_cast<HTMLElement*>(current));
if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) {
foundSelected = static_cast<HTMLOptionElement*>(current);
foundSelected->m_selected = true;
foundSelected->setSelectedState(true);
} else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) {
foundSelected->m_selected = false;
foundSelected->setSelectedState(false);
foundSelected = static_cast<HTMLOptionElement*>(current);
}
}
......@@ -517,7 +521,6 @@ void HTMLSelectElement::recalcListItems() const
current = parent->nextSibling();
}
}
m_lastOnChangeIndex = -1;
m_recalcListItems = false;
}
......@@ -552,38 +555,34 @@ void HTMLSelectElement::reset()
if (items[i]->hasLocalName(optionTag)) {
HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[i]);
if (!option->getAttribute(selectedAttr).isNull()) {
option->setSelected(true);
option->setSelectedState(true);
optionSelected = true;
} else
option->setSelected(false);
option->setSelectedState(false);
if (!firstOption)
firstOption = option;
}
}
if (!optionSelected && firstOption && usesMenuList())
firstOption->setSelected(true);
firstOption->setSelectedState(true);
setChanged(true);
m_lastOnChangeIndex = -1;
}
void HTMLSelectElement::notifyOptionSelected(HTMLOptionElement* selectedOption, bool selected)
void HTMLSelectElement::dispatchFocusEvent()
{
if (selected && !m_multiple)
deselectItems(selectedOption);
scrollToSelection();
m_lastOnChangeIndex = selectedOption->index();
setChanged(true);
#if !ARROW_KEYS_POP_MENU
if (usesMenuList())
saveLastSelection();
#endif
HTMLGenericFormElement::dispatchFocusEvent();
}
void HTMLSelectElement::dispatchBlurEvent()
{
#if !ARROW_KEYS_POP_MENU
if (usesMenuList() && selectedIndex() != m_lastOnChangeIndex) {
m_lastOnChangeIndex = selectedIndex();
onChange();
}
if (usesMenuList())
menuListOnChange();
#endif
HTMLGenericFormElement::dispatchBlurEvent();
}
......@@ -633,6 +632,7 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* evt)
}
if ((keyIdentifier == "Down" || keyIdentifier == "Up" || keyIdentifier == "U+000020") && renderer() && usesMenuList()) {
focus();
saveLastSelection();
menuList->showPopup();
handled = true;
}
......@@ -657,6 +657,7 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* evt)
setSelectedIndex(listToOptionIndex(listIndex));
handled = true;
} else if (keyIdentifier == "Enter") {
saveLastSelection();
setSelectedIndex(listToOptionIndex(listIndex), true, true);
}
#endif
......@@ -668,8 +669,10 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* evt)
focus();
if (menuList->popupIsVisible())
menuList->hidePopup();
else
else {
saveLastSelection();
menuList->showPopup();
}
evt->setDefaultHandled();
}
}
......@@ -681,9 +684,12 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
if (evt->type() == mousedownEvent) {
focus();
MouseEvent* mEvt = static_cast<MouseEvent*>(evt);
int listIndex = static_cast<RenderListBox*>(renderer())->listIndexAtOffset(mEvt->offsetX(), mEvt->offsetY());
if (listIndex >= 0) {
saveLastSelection();
m_activeSelectionState = true;
bool multiSelectKeyPressed = false;
......@@ -706,7 +712,7 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
m_activeSelectionState = false;
if (!m_activeSelectionState)
option->m_selected = false;
option->setSelectedState(false);
}
// If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option.
......@@ -720,7 +726,7 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
// Set the selection state of the clicked option
if (option && !option->disabled())
option->m_selected = true;
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.
......@@ -742,7 +748,7 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
if (!evt->isKeyboardEvent())
return;
String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier();
if (form() && keyIdentifier == "Enter") {
blur();
// Make sure the form hasn't been destroyed during the blur.
......@@ -768,6 +774,8 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt)
}
if (keyIdentifier == "Down" || keyIdentifier == "Up") {
saveLastSelection();
ASSERT(endIndex >= 0 && (unsigned)endIndex < listItems().size());
setActiveSelectionEndIndex(endIndex);
......@@ -820,11 +828,11 @@ void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
if (!option->disabled()) {
if (i >= start && i <= end)
option->m_selected = m_activeSelectionState;
option->setSelectedState(m_activeSelectionState);
else if (deselectOtherOptions)
option->m_selected = false;
option->setSelectedState(false);
else
option->m_selected = m_cachedStateForActiveSelection[i];
option->setSelectedState(m_cachedStateForActiveSelection[i]);
}
}
}
......@@ -832,20 +840,18 @@ void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
scrollToSelection();
}
void HTMLSelectElement::menuListOnChange()
{
if (m_lastOnChangeIndex != selectedIndex())
onChange();
}
void HTMLSelectElement::listBoxOnChange()
{
const Vector<HTMLElement*>& items = listItems();
// If the cached selection list is empty, or the size has changed, then rebuild the list, fire onChange, and return early.
// If the cached selection list is empty, or the size has changed, then fire onChange, and return early.
if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != items.size()) {
m_lastOnChangeSelection.clear();
for (unsigned i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag)) {
HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
m_lastOnChangeSelection.append(option->selected());
} else
m_lastOnChangeSelection.append(false);
}
onChange();
return;
}
......@@ -864,6 +870,24 @@ void HTMLSelectElement::listBoxOnChange()
onChange();
}
void HTMLSelectElement::saveLastSelection()
{
const Vector<HTMLElement*>& items = listItems();
if (usesMenuList()) {
m_lastOnChangeIndex = selectedIndex();
} else {
m_lastOnChangeSelection.clear();
for (unsigned i = 0; i < items.size(); i++) {
if (items[i]->hasLocalName(optionTag)) {
HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]);
m_lastOnChangeSelection.append(option->selected());
} else
m_lastOnChangeSelection.append(false);
}
}
}
static String stripLeadingWhiteSpace(const String& string)
{
int length = string.length();
......
......@@ -56,11 +56,11 @@ public:
virtual void recalcStyle(StyleChange);
virtual void dispatchFocusEvent();
virtual void dispatchBlurEvent();
int selectedIndex() const;
void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false);
void notifyOptionSelected(HTMLOptionElement* selectedOption, bool selected);
int lastSelectedListIndex() const;
virtual bool isEnumeratable() const { return true; }
......@@ -131,6 +131,7 @@ public:
void setActiveSelectionEndIndex(int index) { m_activeSelectionEndIndex = index; }
void updateListBoxSelection(bool deselectOtherOptions);
void listBoxOnChange();
void menuListOnChange();
int activeSelectionStartListIndex() const;
int activeSelectionEndListIndex() const;
......@@ -146,6 +147,7 @@ private:
void menuListDefaultEventHandler(Event*);
void listBoxDefaultEventHandler(Event*);
void typeAheadFind(KeyboardEvent*);
void saveLastSelection();
mutable Vector<HTMLElement*> m_listItems;
Vector<bool> m_cachedStateForActiveSelection;
......
......@@ -83,7 +83,7 @@ public:
int listIndexAtPoint(const IntPoint&) const;
bool setFocusedIndex(int index, bool hotTracking = false, bool fireOnChange = false);
bool setFocusedIndex(int index, bool hotTracking = false);
int focusedIndex() const;
void focusFirst();
void focusLast();
......@@ -139,6 +139,7 @@ private: