15f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian/* 25f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 35f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * 45f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * This library is free software; you can redistribute it and/or 55f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * modify it under the terms of the GNU Library General Public 65f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * License as published by the Free Software Foundation; either 75f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * version 2 of the License, or (at your option) any later version. 85f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * 95f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * This library is distributed in the hope that it will be useful, 105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * but WITHOUT ANY WARRANTY; without even the implied warranty of 115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * Library General Public License for more details. 135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * 145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * You should have received a copy of the GNU Library General Public License 155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * along with this library; see the file COPYING.LIB. If not, write to 165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * Boston, MA 02110-1301, USA. 185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian * 195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian */ 205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "config.h" 225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "SelectElement.h" 235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 24e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "Attribute.h" 25d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "Chrome.h" 265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "ChromeClient.h" 275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "Element.h" 285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "EventHandler.h" 295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "EventNames.h" 305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "FormDataList.h" 315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "Frame.h" 325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "HTMLFormElement.h" 33e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block#include "HTMLNames.h" 345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "HTMLSelectElement.h" 355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "KeyboardEvent.h" 365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "MouseEvent.h" 375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "OptionElement.h" 385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "OptionGroupElement.h" 395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "Page.h" 405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "RenderListBox.h" 415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "RenderMenuList.h" 4228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "SpatialNavigation.h" 435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include <wtf/Assertions.h> 442fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h> 455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ENABLE(WML) 475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "WMLNames.h" 485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "WMLSelectElement.h" 495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif 505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// Configure platform-specific behavior when focused pop-up receives arrow/space/return keystroke. 52231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block// (PLATFORM(MAC) and PLATFORM(GTK) are always false in Chromium, hence the extra tests.) 53d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) 545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#define ARROW_KEYS_POP_MENU 1 550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define SPACE_OR_RETURN_POP_MENU 0 56bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen#elif PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(LINUX) || OS(FREEBSD))) 570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define ARROW_KEYS_POP_MENU 0 580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define SPACE_OR_RETURN_POP_MENU 1 595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else 605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#define ARROW_KEYS_POP_MENU 0 610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define SPACE_OR_RETURN_POP_MENU 0 625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif 635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing std::min; 655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing std::max; 665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing namespace WTF; 675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianusing namespace Unicode; 685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiannamespace WebCore { 705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic const DOMTimeStamp typeAheadTimeout = 1000; 725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochenum SkipDirection { 742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch SkipBackwards = -1, 752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch SkipForwards = 1 762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}; 772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Returns the 1st valid item |skip| items from |listIndex| in direction |direction| if there is one. 792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Otherwise, it returns the valid item closest to that boundary which is past |listIndex| if there is one. 802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Otherwise, it returns |listIndex|. 812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Valid means that it is enabled and an option element. 822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int nextValidIndex(const Vector<Element*>& listItems, int listIndex, SkipDirection direction, int skip) 832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch ASSERT(direction == -1 || direction == 1); 852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int lastGoodIndex = listIndex; 862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int size = listItems.size(); 872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) { 882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch --skip; 892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!listItems[listIndex]->disabled() && isOptionElement(listItems[listIndex])) { 902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch lastGoodIndex = listIndex; 912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (skip <= 0) 922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch break; 932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return lastGoodIndex; 962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int nextSelectableListIndex(SelectElementData& data, Element* element, int startIndex) 992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return nextValidIndex(data.listItems(element), startIndex, SkipForwards, 1); 1012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 1022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int previousSelectableListIndex(SelectElementData& data, Element* element, int startIndex) 1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (startIndex == -1) 1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch startIndex = data.listItems(element).size(); 1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return nextValidIndex(data.listItems(element), startIndex, SkipBackwards, 1); 1082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int firstSelectableListIndex(SelectElementData& data, Element* element) 1112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch const Vector<Element*>& items = data.listItems(element); 1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int index = nextValidIndex(items, items.size(), SkipBackwards, INT_MAX); 1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (static_cast<unsigned>(index) == items.size()) 1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return -1; 1162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return index; 1172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 1182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 1192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int lastSelectableListIndex(SelectElementData& data, Element* element) 1202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 1212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return nextValidIndex(data.listItems(element), -1, SkipForwards, INT_MAX); 1222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 1232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 1242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch// Returns the index of the next valid item one page away from |startIndex| in direction |direction|. 1252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int nextSelectableListIndexPageAway(SelectElementData& data, Element* element, int startIndex, SkipDirection direction) 1262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 1272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch const Vector<Element*>& items = data.listItems(element); 1282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // Can't use data->size() because renderer forces a minimum size. 1292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int pageSize = 0; 1302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (element->renderer()->isListBox()) 1312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch pageSize = toRenderListBox(element->renderer())->size() - 1; // -1 so we still show context 1322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 1332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // One page away, but not outside valid bounds. 1342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // If there is a valid option item one page away, the index is chosen. 1352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // If there is no exact one page away valid option, returns startIndex or the most far index. 1362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1); 1372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex)); 1382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return nextValidIndex(items, edgeIndex, direction, skipAmount); 1392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 1402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 1415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::selectAll(SelectElementData& data, Element* element) 1425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ASSERT(!data.usesMenuList()); 1445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!element->renderer() || !data.multiple()) 1455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 1465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Save the selection so it can be compared to the new selectAll selection when dispatching change events 1485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian saveLastSelection(data, element); 1495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setActiveSelectionState(true); 1515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setActiveSelectionAnchorIndex(data, element, nextSelectableListIndex(data, element, -1)); 1525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setActiveSelectionEndIndex(data, previousSelectableListIndex(data, element, -1)); 1535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian updateListBoxSelection(data, element, false); 1555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listBoxOnChange(data, element); 1565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 1575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::saveLastSelection(SelectElementData& data, Element* element) 1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.usesMenuList()) { 1615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setLastOnChangeIndex(selectedIndex(data, element)); 1625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 1635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 1645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Vector<bool>& lastOnChangeSelection = data.lastOnChangeSelection(); 1665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian lastOnChangeSelection.clear(); 1675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 1695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 1705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 1715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian lastOnChangeSelection.append(optionElement && optionElement->selected()); 1725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 1735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 1745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::setActiveSelectionAnchorIndex(SelectElementData& data, Element* element, int index) 1765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setActiveSelectionAnchorIndex(index); 1785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Cache the selection state so we can restore the old selection as the new selection pivots around this anchor index 1805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Vector<bool>& cachedStateForActiveSelection = data.cachedStateForActiveSelection(); 1815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian cachedStateForActiveSelection.clear(); 1825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 1845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 1855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 1865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian cachedStateForActiveSelection.append(optionElement && optionElement->selected()); 1875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 1885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 1895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::setActiveSelectionEndIndex(SelectElementData& data, int index) 1915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setActiveSelectionEndIndex(index); 1935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 1945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::updateListBoxSelection(SelectElementData& data, Element* element, bool deselectOtherOptions) 1965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ASSERT(element->renderer() && (element->renderer()->isListBox() || data.multiple())); 198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ASSERT(!data.listItems(element).size() || data.activeSelectionAnchorIndex() >= 0); 1995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian unsigned start = min(data.activeSelectionAnchorIndex(), data.activeSelectionEndIndex()); 2015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian unsigned end = max(data.activeSelectionAnchorIndex(), data.activeSelectionEndIndex()); 2025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Vector<bool>& cachedStateForActiveSelection = data.cachedStateForActiveSelection(); 2035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 2055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 2065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 2075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!optionElement || items[i]->disabled()) 2085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian continue; 2095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (i >= start && i <= end) 2115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(data.activeSelectionState()); 2125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else if (deselectOtherOptions || i >= cachedStateForActiveSelection.size()) 2135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(false); 2145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else 2155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(cachedStateForActiveSelection[i]); 2165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 218f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch toSelectElement(element)->updateValidity(); 2195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian scrollToSelection(data, element); 2205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 2215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::listBoxOnChange(SelectElementData& data, Element* element) 2235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ASSERT(!data.usesMenuList() || data.multiple()); 2255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Vector<bool>& lastOnChangeSelection = data.lastOnChangeSelection(); 2275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 2285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // If the cached selection list is empty, or the size has changed, then fire dispatchFormControlChangeEvent, and return early. 2305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (lastOnChangeSelection.isEmpty() || lastOnChangeSelection.size() != items.size()) { 2315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->dispatchFormControlChangeEvent(); 2325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 2335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Update lastOnChangeSelection and fire dispatchFormControlChangeEvent 2365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool fireOnChange = false; 2375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 2385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 2395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool selected = optionElement && optionElement->selected(); 2405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (selected != lastOnChangeSelection[i]) 2415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian fireOnChange = true; 2425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian lastOnChangeSelection[i] = selected; 2435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (fireOnChange) 2465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->dispatchFormControlChangeEvent(); 2475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 2485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::menuListOnChange(SelectElementData& data, Element* element) 2505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 2515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ASSERT(data.usesMenuList()); 2525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int selected = selectedIndex(data, element); 2540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (data.lastOnChangeIndex() != selected && data.userDrivenChange()) { 2555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setLastOnChangeIndex(selected); 2560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch data.setUserDrivenChange(false); 2575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->dispatchFormControlChangeEvent(); 2585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 2605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::scrollToSelection(SelectElementData& data, Element* element) 2625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 2635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.usesMenuList()) 2645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 2655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (RenderObject* renderer = element->renderer()) 2670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch toRenderListBox(renderer)->selectionChanged(); 2685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 2695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 270d0825bca7fe65beaee391d30da42e937db621564Steve Blockvoid SelectElement::setOptionsChangedOnRenderer(SelectElementData& data, Element* element) 2715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 272d0825bca7fe65beaee391d30da42e937db621564Steve Block if (RenderObject* renderer = element->renderer()) { 2735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.usesMenuList()) 2740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch toRenderMenuList(renderer)->setOptionsChanged(true); 2755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else 2760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch toRenderListBox(renderer)->setOptionsChanged(true); 277d0825bca7fe65beaee391d30da42e937db621564Steve Block } 2785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 2795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::setRecalcListItems(SelectElementData& data, Element* element) 2815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 2825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setShouldRecalcListItems(true); 2835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setActiveSelectionAnchorIndex(-1); // Manual selection anchor is reset when manipulating the select programmatically. 284d0825bca7fe65beaee391d30da42e937db621564Steve Block setOptionsChangedOnRenderer(data, element); 2855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->setNeedsStyleRecalc(); 2865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 2875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 2885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::recalcListItems(SelectElementData& data, const Element* element, bool updateSelectedStates) 2895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 2905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Vector<Element*>& listItems = data.rawListItems(); 2915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listItems.clear(); 2925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 293d0825bca7fe65beaee391d30da42e937db621564Steve Block data.setShouldRecalcListItems(false); 294d0825bca7fe65beaee391d30da42e937db621564Steve Block 2955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* foundSelected = 0; 2965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (Node* currentNode = element->firstChild(); currentNode;) { 2975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!currentNode->isElementNode()) { 2985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian currentNode = currentNode->traverseNextSibling(element); 2995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian continue; 3005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Element* current = static_cast<Element*>(currentNode); 3035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // optgroup tags may not nest. However, both FireFox and IE will 3055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // flatten the tree automatically, so we follow suit. 3065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // (http://www.w3.org/TR/html401/interact/forms.html#h-17.6) 3075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (isOptionGroupElement(current)) { 3085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listItems.append(current); 3095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (current->firstChild()) { 3105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian currentNode = current->firstChild(); 3115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian continue; 3125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = toOptionElement(current)) { 3165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listItems.append(current); 3175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 318dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (updateSelectedStates && !data.multiple()) { 319dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!foundSelected && (data.size() <= 1 || optionElement->selected())) { 3205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian foundSelected = optionElement; 3215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian foundSelected->setSelectedState(true); 322dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else if (foundSelected && optionElement->selected()) { 3235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian foundSelected->setSelectedState(false); 3245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian foundSelected = optionElement; 3255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (current->hasTagName(HTMLNames::hrTag)) 3305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listItems.append(current); 3315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // In conforming HTML code, only <optgroup> and <option> will be found 3335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // within a <select>. We call traverseNextSibling so that we only step 3345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // into those tags that we choose to. For web-compat, we should cope 3355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // with the case where odd tags like a <div> have been added but we 3365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // handle this because such tags have already been removed from the 3375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // <select>'s subtree at this point. 3385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian currentNode = currentNode->traverseNextSibling(element); 3395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 3415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::selectedIndex(const SelectElementData& data, const Element* element) 3435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 3445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian unsigned index = 0; 3455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // return the number of the first option selected 3475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 3485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (size_t i = 0; i < items.size(); ++i) { 3495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = toOptionElement(items[i])) { 3505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (optionElement->selected()) 3515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return index; 3525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ++index; 3535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return -1; 3575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 3585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid SelectElement::setSelectedIndex(SelectElementData& data, Element* element, int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange) 3605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 3612fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (optionIndex == -1 && !deselect && !data.multiple()) 3622fc2651226baac27029e38c9d6ef883fa32084dbSteve Block optionIndex = nextSelectableListIndex(data, element, -1); 3635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!data.multiple()) 3645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian deselect = true; 3655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3662fc2651226baac27029e38c9d6ef883fa32084dbSteve Block const Vector<Element*>& items = data.listItems(element); 3672fc2651226baac27029e38c9d6ef883fa32084dbSteve Block int listIndex = optionToListIndex(data, element, optionIndex); 3682fc2651226baac27029e38c9d6ef883fa32084dbSteve Block 3695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Element* excludeElement = 0; 3705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = (listIndex >= 0 ? toOptionElement(items[listIndex]) : 0)) { 3715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian excludeElement = items[listIndex]; 3725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.activeSelectionAnchorIndex() < 0 || deselect) 3735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setActiveSelectionAnchorIndex(data, element, listIndex); 3745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.activeSelectionEndIndex() < 0 || deselect) 3755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setActiveSelectionEndIndex(data, listIndex); 3765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(true); 3775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (deselect) 3805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian deselectItems(data, element, excludeElement); 3815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // For the menu list case, this is what makes the selected element appear. 3835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (RenderObject* renderer = element->renderer()) 3845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian renderer->updateFromElement(); 3855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian scrollToSelection(data, element); 3875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 3880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // This only gets called with fireOnChangeNow for menu lists. 3890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (data.usesMenuList()) { 3900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch data.setUserDrivenChange(userDrivenChange); 3910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (fireOnChangeNow) 3920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch menuListOnChange(data, element); 39306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen RenderObject* renderer = element->renderer(); 39406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (renderer) { 39506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen if (data.usesMenuList()) 39606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen toRenderMenuList(renderer)->didSetSelectedIndex(); 39706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen else if (renderer->isListBox()) 39806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen toRenderListBox(renderer)->selectionChanged(); 39906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen } 4000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 4015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (Frame* frame = element->document()->frame()) 4035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian frame->page()->chrome()->client()->formStateDidChange(element); 4045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::optionToListIndex(const SelectElementData& data, const Element* element, int optionIndex) 4075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 4095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int listSize = (int) items.size(); 4105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (optionIndex < 0 || optionIndex >= listSize) 4115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return -1; 4125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int optionIndex2 = -1; 4145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (int listIndex = 0; listIndex < listSize; ++listIndex) { 4155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (isOptionElement(items[listIndex])) { 4165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ++optionIndex2; 4175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (optionIndex2 == optionIndex) 4185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return listIndex; 4195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 4205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 4215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return -1; 4235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::listToOptionIndex(const SelectElementData& data, const Element* element, int listIndex) 4265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 4285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (listIndex < 0 || listIndex >= int(items.size()) || 4295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian !isOptionElement(items[listIndex])) 4305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return -1; 4315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list 4335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (int i = 0; i < listIndex; ++i) 4345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (isOptionElement(items[i])) 4355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ++optionIndex; 4365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return optionIndex; 4385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::dispatchFocusEvent(SelectElementData& data, Element* element) 4415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Save the selection so it can be compared to the new selection when dispatching change events during blur event dispatchal 4435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.usesMenuList()) 4445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian saveLastSelection(data, element); 4455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::dispatchBlurEvent(SelectElementData& data, Element* element) 4485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // We only need to fire change events here for menu lists, because we fire change events for list boxes whenever the selection change is actually made. 4505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // This matches other browsers' behavior. 4515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.usesMenuList()) 4525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian menuListOnChange(data, element); 4535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::deselectItems(SelectElementData& data, Element* element, Element* excludeElement) 4565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 4585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 4595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (items[i] == excludeElement) 4605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian continue; 4615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = toOptionElement(items[i])) 4635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(false); 4645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 4655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool SelectElement::saveFormControlState(const SelectElementData& data, const Element* element, String& value) 4685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 4705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int length = items.size(); 4715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // FIXME: Change this code to use the new StringImpl::createUninitialized code path. 4735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Vector<char, 1024> characters(length); 4745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (int i = 0; i < length; ++i) { 4755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 4765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool selected = optionElement && optionElement->selected(); 4775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian characters[i] = selected ? 'X' : '.'; 4785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 4795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian value = String(characters.data(), length); 4815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return true; 4825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::restoreFormControlState(SelectElementData& data, Element* element, const String& state) 4855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian recalcListItems(data, element); 4875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 4895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int length = items.size(); 4905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 4915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (int i = 0; i < length; ++i) { 4925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = toOptionElement(items[i])) 4935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(state[i] == 'X'); 4945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 4955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 496d0825bca7fe65beaee391d30da42e937db621564Steve Block setOptionsChangedOnRenderer(data, element); 4975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 499e78cbe89e6f337f2f1fe40315be88f742b547151Steve Blockvoid SelectElement::parseMultipleAttribute(SelectElementData& data, Element* element, Attribute* attribute) 5005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 5015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool oldUsesMenuList = data.usesMenuList(); 5025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setMultiple(!attribute->isNull()); 503f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch toSelectElement(element)->updateValidity(); 5045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (oldUsesMenuList != data.usesMenuList() && element->attached()) { 5055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->detach(); 5065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->attach(); 5075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 5085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 5095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool SelectElement::appendFormData(SelectElementData& data, Element* element, FormDataList& list) 5115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 5125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const AtomicString& name = element->formControlName(); 5135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (name.isEmpty()) 5145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return false; 5155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool successful = false; 5175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 5185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 5205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 521dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (optionElement && optionElement->selected() && !optionElement->disabled()) { 5225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian list.appendData(name, optionElement->value()); 5235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian successful = true; 5245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 5255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 5265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 527dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // It's possible that this is a menulist with multiple options and nothing 528dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // will be submitted (!successful). We won't send a unselected non-disabled 529dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // option as fallback. This behavior matches to other browsers. 5305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return successful; 5315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 5325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::reset(SelectElementData& data, Element* element) 5345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 5355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* firstOption = 0; 5360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch OptionElement* selectedOption = 0; 5375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 5395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (unsigned i = 0; i < items.size(); ++i) { 5405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[i]); 5415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!optionElement) 5425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian continue; 5435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 544f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch if (items[i]->fastHasAttribute(HTMLNames::selectedAttr)) { 5450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (selectedOption && !data.multiple()) 5460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch selectedOption->setSelectedState(false); 5475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(true); 5480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch selectedOption = optionElement; 5495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } else 5505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(false); 5515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!firstOption) 5535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian firstOption = optionElement; 5545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 5555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 556dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!selectedOption && firstOption && !data.multiple() && data.size() <= 1) 5575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian firstOption->setSelectedState(true); 5585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 559d0825bca7fe65beaee391d30da42e937db621564Steve Block setOptionsChangedOnRenderer(data, element); 5605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->setNeedsStyleRecalc(); 5615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 5625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 563ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) 5645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 5655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->type() == eventNames().keydownEvent) { 5665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!element->renderer() || !event->isKeyboardEvent()) 5675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 5685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5696b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier(); 5705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool handled = false; 5715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ARROW_KEYS_POP_MENU 5736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner if (!isSpatialNavigationEnabled(element->document()->frame())) { 5746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner if (keyIdentifier == "Down" || keyIdentifier == "Up") { 5756b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner element->focus(); 576a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 5776b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event. 5786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner return; 579a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 5806b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex, 5816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. 5826b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner saveLastSelection(data, element); 5836b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner if (RenderMenuList* menuList = toRenderMenuList(element->renderer())) 5846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner menuList->showPopup(); 5856b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner 5866b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner event->setDefaultHandled(); 5876b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner } 5886b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner return; 5895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 5906b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#endif 591a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // When using spatial navigation, we want to be able to navigate away from the select element 592a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch // when the user hits any of the arrow keys, instead of changing the selection. 59328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (isSpatialNavigationEnabled(element->document()->frame())) 59428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (!data.activeSelectionState()) 595a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 596a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 597e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block UNUSED_PARAM(htmlForm); 5985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& listItems = data.listItems(element); 5995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 6005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int listIndex = optionToListIndex(data, element, selectedIndex(data, element)); 6015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (keyIdentifier == "Down" || keyIdentifier == "Right") { 6020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 1); 6035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian handled = true; 6045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } else if (keyIdentifier == "Up" || keyIdentifier == "Left") { 6050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch listIndex = nextValidIndex(listItems, listIndex, SkipBackwards, 1); 6060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch handled = true; 6070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else if (keyIdentifier == "PageDown") { 6080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 3); 6090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch handled = true; 6100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else if (keyIdentifier == "PageUp") { 6110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch listIndex = nextValidIndex(listItems, listIndex, SkipBackwards, 3); 6120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch handled = true; 6130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else if (keyIdentifier == "Home") { 6140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch listIndex = nextValidIndex(listItems, -1, SkipForwards, 1); 6150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch handled = true; 6160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } else if (keyIdentifier == "End") { 6170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch listIndex = nextValidIndex(listItems, listItems.size(), SkipBackwards, 1); 6185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian handled = true; 6195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 6202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 6212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (handled && listIndex >= 0 && static_cast<unsigned>(listIndex) < listItems.size()) 6220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex)); 6236b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner 6245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (handled) 6255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian event->setDefaultHandled(); 6265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 6275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 6285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Use key press event here since sending simulated mouse events 6295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // on key down blocks the proper sending of the key press event. 6305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->type() == eventNames().keypressEvent) { 6315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!element->renderer() || !event->isKeyboardEvent()) 6325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 6335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 6345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int keyCode = static_cast<KeyboardEvent*>(event)->keyCode(); 6355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool handled = false; 6365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 6376b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner if (keyCode == ' ' && isSpatialNavigationEnabled(element->document()->frame())) { 6386b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner // Use space to toggle arrow key handling for selection change or spatial navigation. 6396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner data.setActiveSelectionState(!data.activeSelectionState()); 6406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner event->setDefaultHandled(); 6416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner return; 6426b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner } 6436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner 6440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#if SPACE_OR_RETURN_POP_MENU 6450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (keyCode == ' ' || keyCode == '\r') { 6460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch element->focus(); 647a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 648a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event. 649a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 650a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 6510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex, 6520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. 6530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch saveLastSelection(data, element); 6540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (RenderMenuList* menuList = toRenderMenuList(element->renderer())) 6550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch menuList->showPopup(); 6560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch handled = true; 6570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 6580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#elif ARROW_KEYS_POP_MENU 6595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (keyCode == ' ') { 6605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->focus(); 661a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 662a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event. 663a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 664a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 6655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex, 6665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. 6675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian saveLastSelection(data, element); 6680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (RenderMenuList* menuList = toRenderMenuList(element->renderer())) 6695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian menuList->showPopup(); 6705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian handled = true; 6715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } else if (keyCode == '\r') { 672ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block if (htmlForm) 673ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block htmlForm->submitImplicitly(event, false); 6745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian menuListOnChange(data, element); 6755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian handled = true; 6765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 6775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else 6785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int listIndex = optionToListIndex(data, element, selectedIndex(data, element)); 6795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (keyCode == '\r') { 6805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // listIndex should already be selected, but this will fire the onchange handler. 6815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex), true, true); 6825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian handled = true; 6835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 6845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif 6855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (handled) 6865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian event->setDefaultHandled(); 6875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 6885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 6895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { 6905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->focus(); 691231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (element->renderer() && element->renderer()->isMenuList()) { 692231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (RenderMenuList* menuList = toRenderMenuList(element->renderer())) { 693231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (menuList->popupIsVisible()) 694231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block menuList->hidePopup(); 695231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else { 696231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, 697231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. 698231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block saveLastSelection(data, element); 699231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block menuList->showPopup(); 700231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 7015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 7025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 7035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian event->setDefaultHandled(); 7045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 7055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 7065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 707dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid SelectElement::updateSelectedState(SelectElementData& data, Element* element, int listIndex, 708dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool multi, bool shift) 709dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 710dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ASSERT(listIndex >= 0); 711dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 712dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Save the selection so it can be compared to the new selection when dispatching change events during mouseup, or after autoscroll finishes. 713dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block saveLastSelection(data, element); 714dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 715dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block data.setActiveSelectionState(true); 716dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 717dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool shiftSelect = data.multiple() && shift; 718dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool multiSelect = data.multiple() && multi && !shift; 719dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 720dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Element* clickedElement = data.listItems(element)[listIndex]; 721dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block OptionElement* option = toOptionElement(clickedElement); 722dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (option) { 723dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Keep track of whether an active selection (like during drag selection), should select or deselect 724dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (option->selected() && multi) 725dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block data.setActiveSelectionState(false); 726dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 727dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!data.activeSelectionState()) 728dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block option->setSelectedState(false); 729dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 730dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 731dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option. 732dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // If no option was clicked, then this will deselect all items in the list. 733dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!shiftSelect && !multiSelect) 734dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block deselectItems(data, element, clickedElement); 735dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 736dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // 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. 737dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (data.activeSelectionAnchorIndex() < 0 && !multiSelect) 738dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block setActiveSelectionAnchorIndex(data, element, selectedIndex(data, element)); 739dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 740dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Set the selection state of the clicked option 741dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (option && !clickedElement->disabled()) 742dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block option->setSelectedState(true); 743dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 744dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // If there was no selectedIndex() for the previous initialization, or 745dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // 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. 746dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (data.activeSelectionAnchorIndex() < 0 || !shiftSelect) 747dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block setActiveSelectionAnchorIndex(data, element, listIndex); 748dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 749dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block setActiveSelectionEndIndex(data, listIndex); 750dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block updateListBoxSelection(data, element, !multiSelect); 751dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 752dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 753ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) 7545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 7555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& listItems = data.listItems(element); 7565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 7575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { 7585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->focus(); 7595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 760a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event. 761a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch return; 762a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 7635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Convert to coords relative to the list box if needed. 7645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); 7655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian IntPoint localOffset = roundedIntPoint(element->renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); 7660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch int listIndex = toRenderListBox(element->renderer())->listIndexAtOffset(localOffset.x(), localOffset.y()); 7675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (listIndex >= 0) { 768d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) 769dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block updateSelectedState(data, element, listIndex, mouseEvent->metaKey(), mouseEvent->shiftKey()); 7705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else 771dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block updateSelectedState(data, element, listIndex, mouseEvent->ctrlKey(), mouseEvent->shiftKey()); 7725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif 7735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (Frame* frame = element->document()->frame()) 7745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian frame->eventHandler()->setMouseDownMayStartAutoscroll(); 7755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 7765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian event->setDefaultHandled(); 7775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 7786b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner } else if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton && element->document()->frame()->eventHandler()->autoscrollRenderer() != element->renderer()) { 7795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // This makes sure we fire dispatchFormControlChangeEvent for a single click. For drag selection, onChange will fire when the autoscroll timer stops. 7805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listBoxOnChange(data, element); 7816b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner } else if (event->type() == eventNames().keydownEvent) { 7825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!event->isKeyboardEvent()) 7835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 7846b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier(); 7855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 7862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch bool handled = false; 7872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int endIndex = 0; 7885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.activeSelectionEndIndex() < 0) { 7895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Initialize the end index 7902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (keyIdentifier == "Down" || keyIdentifier == "PageDown") { 7912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int startIndex = lastSelectedListIndex(data, element); 7922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 7932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (keyIdentifier == "Down") 7942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = nextSelectableListIndex(data, element, startIndex); 7952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 7962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipForwards); 7972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else if (keyIdentifier == "Up" || keyIdentifier == "PageUp") { 7982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int startIndex = optionToListIndex(data, element, selectedIndex(data, element)); 7992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (keyIdentifier == "Up") 8012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = previousSelectableListIndex(data, element, startIndex); 8022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 8032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipBackwards); 8042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 8055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } else { 8065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Set the end index based on the current end index 8072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (keyIdentifier == "Down") { 8085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian endIndex = nextSelectableListIndex(data, element, data.activeSelectionEndIndex()); 8092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else if (keyIdentifier == "Up") { 8112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex()); 8122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else if (keyIdentifier == "PageDown") { 8142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipForwards); 8152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else if (keyIdentifier == "PageUp") { 8172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipBackwards); 8182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 8202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 8212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (keyIdentifier == "Home") { 8222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = firstSelectableListIndex(data, element); 8232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else if (keyIdentifier == "End") { 8252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch endIndex = lastSelectableListIndex(data, element); 8262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch handled = true; 8275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 82828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 82928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (isSpatialNavigationEnabled(element->document()->frame())) 83028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu // Check if the selection moves to the boundary. 83128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == data.activeSelectionEndIndex())) 83228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu return; 83328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu 8342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (endIndex >= 0 && handled) { 8355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Save the selection so it can be compared to the new selection when dispatching change events immediately after making the new selection. 8365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian saveLastSelection(data, element); 8375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 8382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && static_cast<unsigned>(endIndex) < listItems.size())); 8395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setActiveSelectionEndIndex(data, endIndex); 8402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 84181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch bool selectNewItem = !data.multiple() || static_cast<KeyboardEvent*>(event)->shiftKey() || !isSpatialNavigationEnabled(element->document()->frame()); 84281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (selectNewItem) 84381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch data.setActiveSelectionState(true); 8445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // 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. 84581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch bool deselectOthers = !data.multiple() || (!static_cast<KeyboardEvent*>(event)->shiftKey() && selectNewItem); 8465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.activeSelectionAnchorIndex() < 0 || deselectOthers) { 8475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (deselectOthers) 8485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian deselectItems(data, element); 8495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setActiveSelectionAnchorIndex(data, element, data.activeSelectionEndIndex()); 8505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 8515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 8520bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch toRenderListBox(element->renderer())->scrollToRevealElementAtListIndex(endIndex); 85381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (selectNewItem) { 85481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch updateListBoxSelection(data, element, deselectOthers); 85581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch listBoxOnChange(data, element); 85681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } else 85781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch scrollToSelection(data, element); 85881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 8595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian event->setDefaultHandled(); 8605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 861ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block } else if (event->type() == eventNames().keypressEvent) { 862ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block if (!event->isKeyboardEvent()) 863ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block return; 864ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block int keyCode = static_cast<KeyboardEvent*>(event)->keyCode(); 865ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block 866ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block if (keyCode == '\r') { 867ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block if (htmlForm) 868ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block htmlForm->submitImplicitly(event, false); 869ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block event->setDefaultHandled(); 87081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } else if (data.multiple() && keyCode == ' ' && isSpatialNavigationEnabled(element->document()->frame())) { 87181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch // Use space to toggle selection change. 87281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch data.setActiveSelectionState(!data.activeSelectionState()); 87381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch updateSelectedState(data, element, listToOptionIndex(data, element, data.activeSelectionEndIndex()), true /*multi*/, false /*shift*/); 87481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch listBoxOnChange(data, element); 87581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch event->setDefaultHandled(); 876ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block } 8775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 8785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 8795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 880ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Blockvoid SelectElement::defaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) 8815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 8825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!element->renderer()) 8835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 8845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 8855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (data.usesMenuList()) 886ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block menuListDefaultEventHandler(data, element, event, htmlForm); 8875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else 888ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block listBoxDefaultEventHandler(data, element, event, htmlForm); 8895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 8905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->defaultHandled()) 8915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 8925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 8935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->type() == eventNames().keypressEvent && event->isKeyboardEvent()) { 8945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event); 8955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!keyboardEvent->ctrlKey() && !keyboardEvent->altKey() && !keyboardEvent->metaKey() && isPrintableChar(keyboardEvent->charCode())) { 8965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian typeAheadFind(data, element, keyboardEvent); 8975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian event->setDefaultHandled(); 8985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 8995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 9025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint SelectElement::lastSelectedListIndex(const SelectElementData& data, const Element* element) 9045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 9055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // return the number of the last option selected 9065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian unsigned index = 0; 9075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool found = false; 9085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 9095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (size_t i = 0; i < items.size(); ++i) { 9105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = toOptionElement(items[i])) { 9115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (optionElement->selected()) { 9125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian index = i; 9135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian found = true; 9145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return found ? (int) index : -1; 9195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 9205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic String stripLeadingWhiteSpace(const String& string) 9225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 9235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int length = string.length(); 9245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int i; 9265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (i = 0; i < length; ++i) { 9275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (string[i] != noBreakSpace && (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral))) 9285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian break; 9295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return string.substring(i, length - i); 9325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 9335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::typeAheadFind(SelectElementData& data, Element* element, KeyboardEvent* event) 9355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 9365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (event->timeStamp() < data.lastCharTime()) 9375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 9385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian DOMTimeStamp delta = event->timeStamp() - data.lastCharTime(); 9405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setLastCharTime(event->timeStamp()); 9415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian UChar c = event->charCode(); 9435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian String prefix; 9455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int searchStartOffset = 1; 9465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (delta > typeAheadTimeout) { 9475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian prefix = String(&c, 1); 9485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setTypedString(prefix); 9495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setRepeatingChar(c); 9505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } else { 9515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.typedString().append(c); 9525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (c == data.repeatingChar()) 9545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // The user is likely trying to cycle through all the items starting with this character, so just search on the character 9555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian prefix = String(&c, 1); 9565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else { 9575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian data.setRepeatingChar(0); 9585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian prefix = data.typedString(); 9595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian searchStartOffset = 0; 9605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 9645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int itemCount = items.size(); 9655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (itemCount < 1) 9665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 9675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int selected = selectedIndex(data, element); 9695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int index = (optionToListIndex(data, element, selected >= 0 ? selected : 0) + searchStartOffset) % itemCount; 9705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ASSERT(index >= 0); 9715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 972cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // Compute a case-folded copy of the prefix string before beginning the search for 973cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // a matching element. This code uses foldCase to work around the fact that 974cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // String::startWith does not fold non-ASCII characters. This code can be changed 975cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // to use startWith once that is fixed. 976cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block String prefixWithCaseFolded(prefix.foldCase()); 9775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (int i = 0; i < itemCount; ++i, index = (index + 1) % itemCount) { 9785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian OptionElement* optionElement = toOptionElement(items[index]); 9795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!optionElement || items[index]->disabled()) 9805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian continue; 9815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 982cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block // Fold the option string and check if its prefix is equal to the folded prefix. 9835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian String text = optionElement->textIndentedToRespectGroupLabel(); 984cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block if (stripLeadingWhiteSpace(text).foldCase().startsWith(prefixWithCaseFolded)) { 9855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setSelectedIndex(data, element, listToOptionIndex(data, element, index)); 9865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!data.usesMenuList()) 9875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian listBoxOnChange(data, element); 988d0825bca7fe65beaee391d30da42e937db621564Steve Block 989d0825bca7fe65beaee391d30da42e937db621564Steve Block setOptionsChangedOnRenderer(data, element); 9905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->setNeedsStyleRecalc(); 9915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return; 9925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 9945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 9955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 9965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::insertedIntoTree(SelectElementData& data, Element* element) 9975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 9985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // When the element is created during document parsing, it won't have any items yet - but for innerHTML 9995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // and related methods, this method is called after the whole subtree is constructed. 10005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian recalcListItems(data, element, true); 10015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElement::accessKeySetSelectedIndex(SelectElementData& data, Element* element, int index) 10045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // first bring into focus the list box 10065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!element->focused()) 10075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian element->accessKeyAction(false); 10085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // if this index is already selected, unselect. otherwise update the selected index 10105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian const Vector<Element*>& items = data.listItems(element); 10115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int listIndex = optionToListIndex(data, element, index); 10125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (OptionElement* optionElement = (listIndex >= 0 ? toOptionElement(items[listIndex]) : 0)) { 10135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (optionElement->selected()) 10145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian optionElement->setSelectedState(false); 10155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else 10165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian setSelectedIndex(data, element, index, false, true); 10175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 10184a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch 10194a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch if (data.usesMenuList()) 10204a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch menuListOnChange(data, element); 10214a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch else 10224a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch listBoxOnChange(data, element); 10234a156157940f51b91eadd76f6c86f862ec0a1da0Ben Murdoch 10245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian scrollToSelection(data, element); 10255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochunsigned SelectElement::optionCount(const SelectElementData& data, const Element* element) 10280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{ 10290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch unsigned options = 0; 10300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 10310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch const Vector<Element*>& items = data.listItems(element); 10320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch for (unsigned i = 0; i < items.size(); ++i) { 10330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch if (isOptionElement(items[i])) 10340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch ++options; 10350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch } 10360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 10370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch return options; 10380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch} 10390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 10405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian// SelectElementData 10415f1ab04193ad0130ca8204aadaceae083aca9881Feng QianSelectElementData::SelectElementData() 10425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian : m_multiple(false) 10435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_size(0) 10445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_lastOnChangeIndex(-1) 10455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_activeSelectionState(false) 10465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_activeSelectionAnchorIndex(-1) 10475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_activeSelectionEndIndex(-1) 10485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_recalcListItems(false) 10495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_repeatingChar(0) 10505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian , m_lastCharTime(0) 10515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1054a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochSelectElementData::~SelectElementData() 1055a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{ 1056a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch} 1057a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch 10585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid SelectElementData::checkListItems(const Element* element) const 10595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1060d0825bca7fe65beaee391d30da42e937db621564Steve Block#if !ASSERT_DISABLED 1061dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Vector<Element*> items = m_listItems; 10625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian SelectElement::recalcListItems(*const_cast<SelectElementData*>(this), element, false); 10635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ASSERT(items == m_listItems); 10645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#else 10655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian UNUSED_PARAM(element); 10665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif 10675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10695f1ab04193ad0130ca8204aadaceae083aca9881Feng QianVector<Element*>& SelectElementData::listItems(const Element* element) 10705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (m_recalcListItems) 10725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian SelectElement::recalcListItems(*this, element); 10735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else 10745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian checkListItems(element); 10755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return m_listItems; 10775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianconst Vector<Element*>& SelectElementData::listItems(const Element* element) const 10805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (m_recalcListItems) 10825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian SelectElement::recalcListItems(*const_cast<SelectElementData*>(this), element); 10835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else 10845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian checkListItems(element); 10855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return m_listItems; 10875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10895f1ab04193ad0130ca8204aadaceae083aca9881Feng QianSelectElement* toSelectElement(Element* element) 10905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (element->isHTMLElement() && element->hasTagName(HTMLNames::selectTag)) 10922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return static_cast<HTMLSelectElement*>(element); 10935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ENABLE(WML) 10955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (element->isWMLElement() && element->hasTagName(WMLNames::selectTag)) 10965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return static_cast<WMLSelectElement*>(element); 10975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif 10985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return 0; 11005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 11015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 11025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 1103