[Webkit-unassigned] [Bug 23721] Changing dropdown's selectedIndex within onchange handler fires another onchange
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Tue Jun 23 22:39:41 PDT 2009
https://bugs.webkit.org/show_bug.cgi?id=23721
sam at webkit.org changed:
What |Removed |Added
----------------------------------------------------------------------------
Attachment #31025|review? |review+
Flag| |
------- Comment #5 from sam at webkit.org 2009-06-23 22:39 PDT -------
(From update of attachment 31025)
> Index: WebCore/ChangeLog
> ===================================================================
> --- WebCore/ChangeLog (revision 44476)
> +++ WebCore/ChangeLog (working copy)
> @@ -1,3 +1,34 @@
> +2009-06-05 John Gregg <johnnyg at google.com>
> +
> + Reviewed by NOBODY (OOPS!).
> +
> + Fix for bug 23721: onchange events fire when a SELECT element has
> + focus and the selectedIndex is updated by script in some way--either
> + during another onchange, onkeypress, onfocus, or timer--and then
> + focus is lost.
It is good to add the URL for the bug and the title in the changelogs.
> +
> + Fixed by making a separate method for user-driven selectedIndex
> + changes, leaving scripts to use one which doesn't cause onchange to
> + be queued.
> +
> + Test: fast/forms/select-script-onchange.html
> +
> + * dom/SelectElement.cpp: check if the pending change is user driven
> + before calling onchange
> + (WebCore::SelectElement::menuListOnChange):
> + (WebCore::SelectElement::setSelectedIndex):
> + * dom/SelectElement.h: store whether the pending change is user driven
> + (WebCore::SelectElementData::userDrivenChange):
> + (WebCore::SelectElementData::setUserDrivenChange):
> + * html/HTMLSelectElement.cpp: split into two methods -- script version
> + [non-user-driven] corresponds to IDL defined property name
> + (WebCore::HTMLSelectElement::setSelectedIndex):
> + (WebCore::HTMLSelectElement::setSelectedIndexByUser):
> + * html/HTMLSelectElement.h:
> + * rendering/RenderMenuList.cpp: use ByUser method when coming through
> + the renderer
> + (WebCore::RenderMenuList::valueChanged):
> +
> 2009-06-05 Sam Weinig <sam at webkit.org>
>
> Reviewed by Anders Carlsson.
> Index: WebCore/dom/SelectElement.cpp
> ===================================================================
> --- WebCore/dom/SelectElement.cpp (revision 44474)
> +++ WebCore/dom/SelectElement.cpp (working copy)
> @@ -198,8 +198,9 @@ void SelectElement::menuListOnChange(Sel
> ASSERT(data.usesMenuList());
>
> int selected = selectedIndex(data, element);
> - if (data.lastOnChangeIndex() != selected) {
> + if (data.lastOnChangeIndex() != selected && data.userDrivenChange()) {
> data.setLastOnChangeIndex(selected);
> + data.setUserDrivenChange(false);
> element->dispatchFormControlChangeEvent();
> }
> }
> @@ -309,7 +310,7 @@ int SelectElement::selectedIndex(const S
> return -1;
> }
>
> -void SelectElement::setSelectedIndex(SelectElementData& data, Element* element, int optionIndex, bool deselect, bool fireOnChange)
> +void SelectElement::setSelectedIndex(SelectElementData& data, Element* element, int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange)
> {
> const Vector<Element*>& items = data.listItems(element);
> int listIndex = optionToListIndex(data, element, optionIndex);
> @@ -335,9 +336,12 @@ void SelectElement::setSelectedIndex(Sel
>
> scrollToSelection(data, element);
>
> - // This only gets called with fireOnChange for menu lists.
> - if (fireOnChange && data.usesMenuList())
> - menuListOnChange(data, element);
> + // This only gets called with fireOnChangeNow for menu lists.
> + if (data.usesMenuList()) {
> + data.setUserDrivenChange(userDrivenChange);
> + if (fireOnChangeNow)
> + menuListOnChange(data, element);
> + }
>
> if (Frame* frame = element->document()->frame())
> frame->page()->chrome()->client()->formStateDidChange(element);
> Index: WebCore/dom/SelectElement.h
> ===================================================================
> --- WebCore/dom/SelectElement.h (revision 44474)
> +++ WebCore/dom/SelectElement.h (working copy)
> @@ -57,7 +57,8 @@ public:
> virtual int optionToListIndex(int optionIndex) const = 0;
>
> virtual int selectedIndex() const = 0;
> - virtual void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false) = 0;
> + virtual void setSelectedIndex(int index, bool deselect = true) = 0;
> + virtual void setSelectedIndexByUser(int index, bool deselect = true, bool fireOnChangeNow = false) = 0;
>
> protected:
> virtual ~SelectElement() { }
> @@ -78,7 +79,7 @@ protected:
> static void setRecalcListItems(SelectElementData&, Element*);
> static void recalcListItems(SelectElementData&, const Element*, bool updateSelectedStates = true);
> static int selectedIndex(const SelectElementData&, const Element*);
> - static void setSelectedIndex(SelectElementData&, Element*, int optionIndex, bool deselect = true, bool fireOnChange = false);
> + static void setSelectedIndex(SelectElementData&, Element*, int optionIndex, bool deselect = true, bool fireOnChangeNow = false, bool userDrivenChange = true);
> static int optionToListIndex(const SelectElementData&, const Element*, int optionIndex);
> static int listToOptionIndex(const SelectElementData&, const Element*, int listIndex);
> static void dispatchFocusEvent(SelectElementData&, Element*);
> @@ -117,6 +118,9 @@ public:
> int lastOnChangeIndex() const { return m_lastOnChangeIndex; }
> void setLastOnChangeIndex(int value) { m_lastOnChangeIndex = value; }
>
> + bool userDrivenChange() const { return m_userDrivenChange; }
> + void setUserDrivenChange(bool value) { m_userDrivenChange = value; }
> +
> Vector<bool>& lastOnChangeSelection() { return m_lastOnChangeSelection; }
>
> bool activeSelectionState() const { return m_activeSelectionState; }
> @@ -154,6 +158,7 @@ private:
>
> int m_lastOnChangeIndex;
> Vector<bool> m_lastOnChangeSelection;
> + bool m_userDrivenChange;
>
> bool m_activeSelectionState;
> int m_activeSelectionAnchorIndex;
> Index: WebCore/html/HTMLSelectElement.cpp
> ===================================================================
> --- WebCore/html/HTMLSelectElement.cpp (revision 44474)
> +++ WebCore/html/HTMLSelectElement.cpp (working copy)
> @@ -80,9 +80,14 @@ void HTMLSelectElement::deselectItems(HT
> SelectElement::deselectItems(m_data, this, excludeElement);
> }
>
> -void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChange)
> +void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect)
> {
> - SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChange);
> + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, false, false);
> +}
> +
> +void HTMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow)
> +{
> + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChangeNow, true);
> }
>
> int HTMLSelectElement::activeSelectionStartListIndex() const
> Index: WebCore/html/HTMLSelectElement.h
> ===================================================================
> --- WebCore/html/HTMLSelectElement.h (revision 44474)
> +++ WebCore/html/HTMLSelectElement.h (working copy)
> @@ -39,7 +39,8 @@ public:
> HTMLSelectElement(const QualifiedName&, Document*, HTMLFormElement* = 0);
>
> virtual int selectedIndex() const;
> - virtual void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false);
> + virtual void setSelectedIndex(int index, bool deselect = true);
> + virtual void setSelectedIndexByUser(int index, bool deselect = true, bool fireOnChangeNow = false);
>
> unsigned length() const;
>
> Index: WebCore/rendering/RenderMenuList.cpp
> ===================================================================
> --- WebCore/rendering/RenderMenuList.cpp (revision 44474)
> +++ WebCore/rendering/RenderMenuList.cpp (working copy)
> @@ -297,7 +297,7 @@ void RenderMenuList::hidePopup()
> void RenderMenuList::valueChanged(unsigned listIndex, bool fireOnChange)
> {
> SelectElement* select = toSelectElement(static_cast<Element*>(node()));
> - select->setSelectedIndex(select->listToOptionIndex(listIndex), true, fireOnChange);
> + select->setSelectedIndexByUser(select->listToOptionIndex(listIndex), true, fireOnChange);
> }
>
> String RenderMenuList::itemText(unsigned listIndex) const
> Index: LayoutTests/ChangeLog
> ===================================================================
> --- LayoutTests/ChangeLog (revision 44476)
> +++ LayoutTests/ChangeLog (working copy)
> @@ -1,3 +1,13 @@
> +2009-06-05 John Gregg <johnnyg at google.com>
> +
> + Check for unnecessary calls to onchange in response to script
> + actions.
> +
> + https://bugs.webkit.org/show_bug.cgi?id=23721
> +
> + * fast/forms/select-script-onchange-expected.txt: Added.
> + * fast/forms/select-script-onchange.html: Added.
> +
> 2009-06-01 Ben Murdoch <benm at google.com>
>
> <https://bugs.webkit.org/show_bug.cgi?id=25710> HTML5 Database stops executing transactions if the URL hash changes while a transaction is open and an XHR is in progress.
> Index: LayoutTests/fast/forms/select-script-onchange-expected.txt
> ===================================================================
> --- LayoutTests/fast/forms/select-script-onchange-expected.txt (revision 0)
> +++ LayoutTests/fast/forms/select-script-onchange-expected.txt (revision 0)
> @@ -0,0 +1,7 @@
> +Test for http://bugs.webkit.org/show_bug.cgi?id=23721 Changing dropdown's selectedIndex within onchange handler fires another onchange.
> +
> +SUCCESS
> +
> +This select changes on focus: should not fire onchange.
> +This select changes on change: should only fire onchange once.
> +This select is changed by a timeout in the test script. It should not fire onchange.
> Index: LayoutTests/fast/forms/select-script-onchange.html
> ===================================================================
> --- LayoutTests/fast/forms/select-script-onchange.html (revision 0)
> +++ LayoutTests/fast/forms/select-script-onchange.html (revision 0)
> @@ -0,0 +1,86 @@
> +<html>
> + <head>
> + <title></title>
> + <script type="text/javascript">
> + var changeCount = new Array(4);
> + changeCount[1] = changeCount[2] = changeCount[3] = 0;
> +
> + function test()
> + {
> + if (!window.eventSender)
> + return;
> +
> + layoutTestController.dumpAsText();
> +
> + var popup = document.getElementById("switcher1");
> + popup.focus();
> +
> + popup = document.getElementById("switcher2");
> + popup.focus();
> +
> + eventSender.keyDown("t", null);
> + eventSender.keyDown("\r", null);
> +
> + var popup = document.getElementById("switcher3");
> + popup.focus();
> +
> + check();
> + }
> +
> + function check() {
> + setTimeout("document.getElementById('switcher3').selectedIndex = 1;", 0);
> +
> + var popup = document.getElementById("switcher2");
> + popup.focus();
> +
> + var result = document.getElementById("result");
> + result.innerHTML = "";
> + if (changeCount[1] != 0) {
> + result.innerHTML += "<br/>FAILURE: onchange(1) called " + changeCount[1] + " times.";
> + }
> + if (changeCount[2] != 1) {
> + result.innerHTML += "<br/>FAILURE: onchange(2) called " + changeCount[2] + " times.";
> + }
> + if (changeCount[3] != 0) {
> + result.innerHTML += "<br/>FAILURE: onchange(3) called " + changeCount[3] + " times.";
> + }
> + if (result.innerHTML == "") result.innerHTML = "SUCCESS";
> +
> + }
> +
> + function changed(select)
> + {
> + changeCount[select]++;
> + }
> + </script>
> + </head>
> + <body onload="test()">
> + <p>
> + Test for <i><a href="http://bugs.webkit.org/show_bug.cgi?id=23721">http://bugs.webkit.org/show_bug.cgi?id=23721</a>
> + Changing dropdown's selectedIndex within onchange handler fires another onchange</i>.
> + </p>
> + <p id="result">
> + To test interactively: focus on the first select (don't change it).<br/>
> + Change the second select to "two"<br/>
> + Focus on the third, then click <a href="#" onclick="check(); return false;">here</a>.
> + </p>
> + This select changes on focus: should not fire onchange.
> + <select name="switcher1" id="switcher1" onfocus="this.selectedIndex = 1;" onchange="changed(1)">
> + <option value="one">One</option>
> + <option value="two">Two</option>
> + </select>
> + <hr/>
> + This select changes on change: should only fire onchange once.
> + <select name="switcher2" id="switcher2" onchange="changed(2); if (this.selectedIndex == 1) this.selectedIndex = 2;">
> + <option value="one">One</option>
> + <option value="two">Two</option>
> + <option value="three">Three</option>
> + </select>
> + <hr/>
> + This select is changed by a timeout in the test script. It should not fire onchange.
> + <select name="switcher3" id="switcher3" onchange="changed(3)">
> + <option value="one">One</option>
> + <option value="two">Two</option>
> + </select>
> + </body>
> +</html>
--
Configure bugmail: https://bugs.webkit.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.
More information about the webkit-unassigned
mailing list