OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | 2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 3 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
4 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 4 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
5 * (C) 2001 Dirk Mueller (mueller@kde.org) | 5 * (C) 2001 Dirk Mueller (mueller@kde.org) |
6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights
reserved. | 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights
reserved. |
7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 7 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
8 * Copyright (C) 2010 Google Inc. All rights reserved. | 8 * Copyright (C) 2010 Google Inc. All rights reserved. |
9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.com/) | 9 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.com/) |
10 * | 10 * |
(...skipping 1096 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1107 } | 1107 } |
1108 | 1108 |
1109 if (!selectedOption && firstOption && !m_multiple && m_size <= 1) | 1109 if (!selectedOption && firstOption && !m_multiple && m_size <= 1) |
1110 firstOption->setSelectedState(true); | 1110 firstOption->setSelectedState(true); |
1111 | 1111 |
1112 setOptionsChangedOnRenderer(); | 1112 setOptionsChangedOnRenderer(); |
1113 setNeedsStyleRecalc(SubtreeStyleChange); | 1113 setNeedsStyleRecalc(SubtreeStyleChange); |
1114 setNeedsValidityCheck(); | 1114 setNeedsValidityCheck(); |
1115 } | 1115 } |
1116 | 1116 |
1117 #if !OS(WIN) | 1117 void HTMLSelectElement::handlePopupOpenKeyboardEvent(Event* event) |
1118 bool HTMLSelectElement::platformHandleKeydownEvent(KeyboardEvent* event) | |
1119 { | 1118 { |
1120 if (!RenderTheme::theme().popsMenuByArrowKeys()) | 1119 focus(); |
| 1120 // Calling focus() may cause us to lose our renderer. Return true so |
| 1121 // that our caller doesn't process the event further, but don't set |
| 1122 // the event as handled. |
| 1123 if (!renderer() || !renderer()->isMenuList() || isDisabledFormControl()) |
| 1124 return; |
| 1125 // Save the selection so it can be compared to the new selection |
| 1126 // when dispatching change events during selectOption, which |
| 1127 // gets called from RenderMenuList::valueChanged, which gets called |
| 1128 // after the user makes a selection from the menu. |
| 1129 saveLastSelection(); |
| 1130 if (RenderMenuList* menuList = toRenderMenuList(renderer())) |
| 1131 menuList->showPopup(); |
| 1132 int index = selectedIndex(); |
| 1133 ASSERT(index >= 0); |
| 1134 ASSERT_WITH_SECURITY_IMPLICATION(index < static_cast<int>(listItems().size()
)); |
| 1135 setSelectedIndex(index); |
| 1136 event->setDefaultHandled(); |
| 1137 return; |
| 1138 } |
| 1139 |
| 1140 bool HTMLSelectElement::shouldOpenPopupForKeyDownEvent(KeyboardEvent* keyEvent) |
| 1141 { |
| 1142 const String& keyIdentifier = keyEvent->keyIdentifier(); |
| 1143 RenderTheme& renderTheme = RenderTheme::theme(); |
| 1144 |
| 1145 if (isSpatialNavigationEnabled(document().frame())) |
1121 return false; | 1146 return false; |
1122 | 1147 |
1123 if (!isSpatialNavigationEnabled(document().frame())) { | 1148 return ((renderTheme.popsMenuByArrowKeys() && (keyIdentifier == "Down" || k
eyIdentifier == "Up")) |
1124 if (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up")
{ | 1149 || (renderTheme.popsMenuByAltDownUpOrF4Key() && (keyIdentifier == "Down"
|| keyIdentifier == "Up") && (keyEvent->altKey() || keyEvent->altGraphKey())) |
1125 focus(); | 1150 || (renderTheme.popsMenuByAltDownUpOrF4Key() && (!keyEvent->altKey() &&
!keyEvent->ctrlKey() && keyIdentifier == "F4"))); |
1126 // Calling focus() may cause us to lose our renderer. Return true so | 1151 } |
1127 // that our caller doesn't process the event further, but don't set | |
1128 // the event as handled. | |
1129 if (!renderer() || !renderer()->isMenuList() || isDisabledFormContro
l()) | |
1130 return true; | |
1131 | 1152 |
1132 // Save the selection so it can be compared to the new selection | 1153 bool HTMLSelectElement::shouldOpenPopupForKeyPressEvent(KeyboardEvent *event) |
1133 // when dispatching change events during selectOption, which | 1154 { |
1134 // gets called from RenderMenuList::valueChanged, which gets called | 1155 RenderTheme& renderTheme = RenderTheme::theme(); |
1135 // after the user makes a selection from the menu. | 1156 int keyCode = event->keyCode(); |
1136 saveLastSelection(); | |
1137 if (RenderMenuList* menuList = toRenderMenuList(renderer())) | |
1138 menuList->showPopup(); | |
1139 event->setDefaultHandled(); | |
1140 } | |
1141 return true; | |
1142 } | |
1143 | 1157 |
1144 return false; | 1158 return ((renderTheme.popsMenuBySpaceKey() && event->keyCode() == ' ') |
| 1159 || (renderTheme.popsMenuByReturnKey() && keyCode == '\r')); |
1145 } | 1160 } |
1146 #endif | |
1147 | 1161 |
1148 void HTMLSelectElement::menuListDefaultEventHandler(Event* event) | 1162 void HTMLSelectElement::menuListDefaultEventHandler(Event* event) |
1149 { | 1163 { |
1150 RenderTheme& renderTheme = RenderTheme::theme(); | |
1151 | |
1152 if (event->type() == EventTypeNames::keydown) { | 1164 if (event->type() == EventTypeNames::keydown) { |
1153 if (!renderer() || !event->isKeyboardEvent()) | 1165 if (!renderer() || !event->isKeyboardEvent()) |
1154 return; | 1166 return; |
1155 | 1167 |
1156 if (platformHandleKeydownEvent(toKeyboardEvent(event))) | 1168 KeyboardEvent* keyEvent = toKeyboardEvent(event); |
| 1169 if (shouldOpenPopupForKeyDownEvent(keyEvent)) { |
| 1170 handlePopupOpenKeyboardEvent(event); |
1157 return; | 1171 return; |
| 1172 } |
1158 | 1173 |
1159 // When using spatial navigation, we want to be able to navigate away | 1174 // When using spatial navigation, we want to be able to navigate away |
1160 // from the select element when the user hits any of the arrow keys, | 1175 // from the select element when the user hits any of the arrow keys, |
1161 // instead of changing the selection. | 1176 // instead of changing the selection. |
1162 if (isSpatialNavigationEnabled(document().frame())) { | 1177 if (isSpatialNavigationEnabled(document().frame())) { |
1163 if (!m_activeSelectionState) | 1178 if (!m_activeSelectionState) |
1164 return; | 1179 return; |
1165 } | 1180 } |
1166 | 1181 |
1167 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); | 1182 // The key handling below shouldn't be used for non spatial navigation m
ode Mac |
| 1183 if (RenderTheme::theme().popsMenuByArrowKeys() && !isSpatialNavigationEn
abled(document().frame())) |
| 1184 return; |
| 1185 |
| 1186 const String& keyIdentifier = keyEvent->keyIdentifier(); |
1168 bool handled = true; | 1187 bool handled = true; |
1169 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = th
is->listItems(); | 1188 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = th
is->listItems(); |
1170 int listIndex = optionToListIndex(selectedIndex()); | 1189 int listIndex = optionToListIndex(selectedIndex()); |
1171 | 1190 |
1172 if (keyIdentifier == "Down" || keyIdentifier == "Right") | 1191 if (keyIdentifier == "Down" || keyIdentifier == "Right") |
1173 listIndex = nextValidIndex(listIndex, SkipForwards, 1); | 1192 listIndex = nextValidIndex(listIndex, SkipForwards, 1); |
1174 else if (keyIdentifier == "Up" || keyIdentifier == "Left") | 1193 else if (keyIdentifier == "Up" || keyIdentifier == "Left") |
1175 listIndex = nextValidIndex(listIndex, SkipBackwards, 1); | 1194 listIndex = nextValidIndex(listIndex, SkipBackwards, 1); |
1176 else if (keyIdentifier == "PageDown") | 1195 else if (keyIdentifier == "PageDown") |
1177 listIndex = nextValidIndex(listIndex, SkipForwards, 3); | 1196 listIndex = nextValidIndex(listIndex, SkipForwards, 3); |
1178 else if (keyIdentifier == "PageUp") | 1197 else if (keyIdentifier == "PageUp") |
1179 listIndex = nextValidIndex(listIndex, SkipBackwards, 3); | 1198 listIndex = nextValidIndex(listIndex, SkipBackwards, 3); |
1180 else if (keyIdentifier == "Home") | 1199 else if (keyIdentifier == "Home") |
1181 listIndex = nextValidIndex(-1, SkipForwards, 1); | 1200 listIndex = nextValidIndex(-1, SkipForwards, 1); |
1182 else if (keyIdentifier == "End") | 1201 else if (keyIdentifier == "End") |
1183 listIndex = nextValidIndex(listItems.size(), SkipBackwards, 1); | 1202 listIndex = nextValidIndex(listItems.size(), SkipBackwards, 1); |
1184 else | 1203 else |
1185 handled = false; | 1204 handled = false; |
1186 | 1205 |
1187 if (handled && static_cast<size_t>(listIndex) < listItems.size()) | 1206 if (handled && static_cast<size_t>(listIndex) < listItems.size()) |
1188 selectOption(listToOptionIndex(listIndex), DeselectOtherOptions | Di
spatchInputAndChangeEvent | UserDriven); | 1207 selectOption(listToOptionIndex(listIndex), DeselectOtherOptions | Di
spatchInputAndChangeEvent | UserDriven); |
1189 | 1208 |
1190 if (handled) | 1209 if (handled) |
1191 event->setDefaultHandled(); | 1210 event->setDefaultHandled(); |
1192 } | 1211 } |
1193 | 1212 |
1194 // Use key press event here since sending simulated mouse events | |
1195 // on key down blocks the proper sending of the key press event. | |
1196 if (event->type() == EventTypeNames::keypress) { | 1213 if (event->type() == EventTypeNames::keypress) { |
1197 if (!renderer() || !event->isKeyboardEvent()) | 1214 if (!renderer() || !event->isKeyboardEvent()) |
1198 return; | 1215 return; |
1199 | 1216 |
1200 int keyCode = toKeyboardEvent(event)->keyCode(); | 1217 int keyCode = toKeyboardEvent(event)->keyCode(); |
1201 bool handled = false; | |
1202 | |
1203 if (keyCode == ' ' && isSpatialNavigationEnabled(document().frame())) { | 1218 if (keyCode == ' ' && isSpatialNavigationEnabled(document().frame())) { |
1204 // Use space to toggle arrow key handling for selection change or sp
atial navigation. | 1219 // Use space to toggle arrow key handling for selection change or sp
atial navigation. |
1205 m_activeSelectionState = !m_activeSelectionState; | 1220 m_activeSelectionState = !m_activeSelectionState; |
1206 event->setDefaultHandled(); | 1221 event->setDefaultHandled(); |
1207 return; | 1222 return; |
1208 } | 1223 } |
1209 | 1224 |
1210 if (renderTheme.popsMenuBySpaceOrReturn()) { | 1225 KeyboardEvent* keyEvent = toKeyboardEvent(event); |
1211 if (keyCode == ' ' || keyCode == '\r') { | 1226 if (shouldOpenPopupForKeyPressEvent(keyEvent)) { |
1212 focus(); | 1227 handlePopupOpenKeyboardEvent(event); |
1213 | 1228 return; |
1214 // Calling focus() may remove the renderer or change the | |
1215 // renderer type. | |
1216 if (!renderer() || !renderer()->isMenuList() || isDisabledFormCo
ntrol()) | |
1217 return; | |
1218 | |
1219 // Save the selection so it can be compared to the new selection | |
1220 // when dispatching change events during selectOption, which | |
1221 // gets called from RenderMenuList::valueChanged, which gets cal
led | |
1222 // after the user makes a selection from the menu. | |
1223 saveLastSelection(); | |
1224 if (RenderMenuList* menuList = toRenderMenuList(renderer())) | |
1225 menuList->showPopup(); | |
1226 handled = true; | |
1227 } | |
1228 } else if (renderTheme.popsMenuByArrowKeys()) { | |
1229 if (keyCode == ' ') { | |
1230 focus(); | |
1231 | |
1232 // Calling focus() may remove the renderer or change the | |
1233 // renderer type. | |
1234 if (!renderer() || !renderer()->isMenuList() || isDisabledFormCo
ntrol()) | |
1235 return; | |
1236 | |
1237 // Save the selection so it can be compared to the new selection | |
1238 // when dispatching change events during selectOption, which | |
1239 // gets called from RenderMenuList::valueChanged, which gets cal
led | |
1240 // after the user makes a selection from the menu. | |
1241 saveLastSelection(); | |
1242 if (RenderMenuList* menuList = toRenderMenuList(renderer())) | |
1243 menuList->showPopup(); | |
1244 handled = true; | |
1245 } else if (keyCode == '\r') { | |
1246 if (form()) | |
1247 form()->submitImplicitly(event, false); | |
1248 dispatchInputAndChangeEventForMenuList(); | |
1249 handled = true; | |
1250 } | |
1251 } | 1229 } |
1252 | 1230 |
1253 if (handled) | 1231 if (!RenderTheme::theme().popsMenuByReturnKey() && keyCode == '\r') { |
| 1232 if (form()) |
| 1233 form()->submitImplicitly(event, false); |
| 1234 dispatchInputAndChangeEventForMenuList(); |
1254 event->setDefaultHandled(); | 1235 event->setDefaultHandled(); |
| 1236 } |
1255 } | 1237 } |
1256 | 1238 |
1257 if (event->type() == EventTypeNames::mousedown && event->isMouseEvent() && t
oMouseEvent(event)->button() == LeftButton) { | 1239 if (event->type() == EventTypeNames::mousedown && event->isMouseEvent() && t
oMouseEvent(event)->button() == LeftButton) { |
1258 focus(); | 1240 focus(); |
1259 if (renderer() && renderer()->isMenuList() && !isDisabledFormControl())
{ | 1241 if (renderer() && renderer()->isMenuList() && !isDisabledFormControl())
{ |
1260 if (RenderMenuList* menuList = toRenderMenuList(renderer())) { | 1242 if (RenderMenuList* menuList = toRenderMenuList(renderer())) { |
1261 if (menuList->popupIsVisible()) | 1243 if (menuList->popupIsVisible()) |
1262 menuList->hidePopup(); | 1244 menuList->hidePopup(); |
1263 else { | 1245 else { |
1264 // Save the selection so it can be compared to the new | 1246 // Save the selection so it can be compared to the new |
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1658 | 1640 |
1659 void HTMLSelectElement::trace(Visitor* visitor) | 1641 void HTMLSelectElement::trace(Visitor* visitor) |
1660 { | 1642 { |
1661 #if ENABLE(OILPAN) | 1643 #if ENABLE(OILPAN) |
1662 visitor->trace(m_listItems); | 1644 visitor->trace(m_listItems); |
1663 #endif | 1645 #endif |
1664 HTMLFormControlElementWithState::trace(visitor); | 1646 HTMLFormControlElementWithState::trace(visitor); |
1665 } | 1647 } |
1666 | 1648 |
1667 } // namespace | 1649 } // namespace |
OLD | NEW |