Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Side by Side Diff: Source/WebCore/html/HTMLSelectElement.cpp

Issue 14096013: Implement select element list box with shadow DOM. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@shadowselect
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 #include "HTMLOptionsCollection.h" 44 #include "HTMLOptionsCollection.h"
45 #include "KeyboardEvent.h" 45 #include "KeyboardEvent.h"
46 #include "LocalizedStrings.h" 46 #include "LocalizedStrings.h"
47 #include "MouseEvent.h" 47 #include "MouseEvent.h"
48 #include "NodeRenderingContext.h" 48 #include "NodeRenderingContext.h"
49 #include "NodeTraversal.h" 49 #include "NodeTraversal.h"
50 #include "Page.h" 50 #include "Page.h"
51 #include "RenderListBox.h" 51 #include "RenderListBox.h"
52 #include "RenderMenuList.h" 52 #include "RenderMenuList.h"
53 #include "RenderTheme.h" 53 #include "RenderTheme.h"
54 #include "StyleResolver.h"
54 #include "ScriptEventListener.h" 55 #include "ScriptEventListener.h"
55 #include "SpatialNavigation.h" 56 #include "SpatialNavigation.h"
56 #include <wtf/text/StringBuilder.h> 57 #include <wtf/text/StringBuilder.h>
57 #include <wtf/unicode/Unicode.h> 58 #include <wtf/unicode/Unicode.h>
58 59
59 using namespace std; 60 using namespace std;
60 using namespace WTF::Unicode; 61 using namespace WTF::Unicode;
61 62
62 namespace WebCore { 63 namespace WebCore {
63 64
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 m_lastOnChangeIndex = selected; 668 m_lastOnChangeIndex = selected;
668 m_isProcessingUserDrivenChange = false; 669 m_isProcessingUserDrivenChange = false;
669 dispatchFormControlChangeEvent(); 670 dispatchFormControlChangeEvent();
670 } 671 }
671 } 672 }
672 673
673 void HTMLSelectElement::scrollToSelection() 674 void HTMLSelectElement::scrollToSelection()
674 { 675 {
675 if (usesMenuList()) 676 if (usesMenuList())
676 return; 677 return;
677 678 int listIndex = activeSelectionEndListIndex();
678 if (RenderObject* renderer = this->renderer()) 679 const Vector<HTMLElement*>& items = listItems();
679 toRenderListBox(renderer)->selectionChanged(); 680 int listSize = static_cast<int>(items.size());
681 if (listIndex < 0 || listIndex >= listSize)
682 return;
683 Element* option = listItems()[listIndex];
684 option->scrollIntoViewIfNeeded(false);
680 } 685 }
681 686
682 void HTMLSelectElement::setOptionsChangedOnRenderer() 687 void HTMLSelectElement::setOptionsChangedOnRenderer()
683 { 688 {
684 if (RenderObject* renderer = this->renderer()) { 689 if (RenderObject* renderer = this->renderer()) {
685 if (usesMenuList()) 690 if (usesMenuList())
686 toRenderMenuList(renderer)->setOptionsChanged(true); 691 toRenderMenuList(renderer)->setOptionsChanged(true);
687 else 692 // else
688 toRenderListBox(renderer)->setOptionsChanged(true); 693 // scrollToSelection();
689 } 694 }
690 } 695 }
691 696
692 const Vector<HTMLElement*>& HTMLSelectElement::listItems() const 697 const Vector<HTMLElement*>& HTMLSelectElement::listItems() const
693 { 698 {
694 if (m_shouldRecalcListItems) 699 if (m_shouldRecalcListItems)
695 recalcListItems(); 700 recalcListItems();
696 else { 701 else {
697 #if !ASSERT_DISABLED 702 #if !ASSERT_DISABLED
698 Vector<HTMLElement*> items = m_listItems; 703 Vector<HTMLElement*> items = m_listItems;
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 857
853 scrollToSelection(); 858 scrollToSelection();
854 859
855 if (usesMenuList()) { 860 if (usesMenuList()) {
856 m_isProcessingUserDrivenChange = flags & UserDriven; 861 m_isProcessingUserDrivenChange = flags & UserDriven;
857 if (flags & DispatchChangeEvent) 862 if (flags & DispatchChangeEvent)
858 dispatchChangeEventForMenuList(); 863 dispatchChangeEventForMenuList();
859 if (RenderObject* renderer = this->renderer()) { 864 if (RenderObject* renderer = this->renderer()) {
860 if (usesMenuList()) 865 if (usesMenuList())
861 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); 866 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex);
862 else if (renderer->isListBox())
863 toRenderListBox(renderer)->selectionChanged();
864 } 867 }
865 } 868 }
866 869
867 setNeedsValidityCheck(); 870 setNeedsValidityCheck();
868 notifyFormStateChanged(); 871 notifyFormStateChanged();
869 } 872 }
870 873
871 int HTMLSelectElement::optionToListIndex(int optionIndex) const 874 int HTMLSelectElement::optionToListIndex(int optionIndex) const
872 { 875 {
873 const Vector<HTMLElement*>& items = listItems(); 876 const Vector<HTMLElement*>& items = listItems();
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
1277 // we're doing a single selection, or a multiple selection (using cmd or 1280 // we're doing a single selection, or a multiple selection (using cmd or
1278 // ctrl), then initialize the anchor index to the listIndex that just got 1281 // ctrl), then initialize the anchor index to the listIndex that just got
1279 // clicked. 1282 // clicked.
1280 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) 1283 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect)
1281 setActiveSelectionAnchorIndex(listIndex); 1284 setActiveSelectionAnchorIndex(listIndex);
1282 1285
1283 setActiveSelectionEndIndex(listIndex); 1286 setActiveSelectionEndIndex(listIndex);
1284 updateListBoxSelection(!multiSelect); 1287 updateListBoxSelection(!multiSelect);
1285 } 1288 }
1286 1289
1290 int HTMLSelectElement::listIndexForEvent(Event* event)
1291 {
1292 const Vector<HTMLElement*>& items = this->listItems();
1293 for (Node* node = event->target()->toNode(); node; node = node->parentOrShad owHostNode()) {
1294 if (node->isElementNode() && (toElement(node)->hasTagName(optionTag) || toElement(node)->hasTagName(optgroupTag))) {
1295 size_t length = items.size();
1296 for (size_t i = 0; i < length; ++i) {
1297 if (items[i] == node) {
1298 return i;
1299 }
1300 }
1301 }
1302 }
1303 return -1;
1304 }
1305
1287 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) 1306 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
1288 { 1307 {
1289 const Vector<HTMLElement*>& listItems = this->listItems(); 1308 const Vector<HTMLElement*>& listItems = this->listItems();
1290 1309
1291 if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { 1310 if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
1292 focus(); 1311 focus();
1293 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event. 1312 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event.
1294 if (!renderer()) 1313 if (!renderer())
1295 return; 1314 return;
1296 1315
1297 // Convert to coords relative to the list box if needed.
1298 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); 1316 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
1299 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); 1317 int listIndex = listIndexForEvent(event);
1300 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1301 if (listIndex >= 0) { 1318 if (listIndex >= 0) {
1302 if (!isDisabledFormControl()) { 1319 if (!isDisabledFormControl()) {
1303 #if OS(DARWIN) 1320 #if OS(DARWIN)
1304 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey()); 1321 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey());
1305 #else 1322 #else
1306 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey()); 1323 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey());
1307 #endif 1324 #endif
1308 } 1325 }
1309 if (Frame* frame = document()->frame()) 1326 if (Frame* frame = document()->frame())
1310 frame->eventHandler()->setMouseDownMayStartAutoscroll(); 1327 frame->eventHandler()->setMouseDownMayStartAutoscroll();
1311 1328
1312 event->setDefaultHandled(); 1329 event->setDefaultHandled();
1313 } 1330 }
1314 } else if (event->type() == eventNames().mousemoveEvent && event->isMouseEve nt() && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { 1331 } else if (event->type() == eventNames().mousemoveEvent && event->isMouseEve nt()) {
1315 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); 1332 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
1316 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) 1333 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown())
1317 return; 1334 return;
1318 1335
1319 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); 1336 int listIndex = listIndexForEvent(event);
1320 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1321 if (listIndex >= 0) { 1337 if (listIndex >= 0) {
1322 if (!isDisabledFormControl()) { 1338 if (!isDisabledFormControl()) {
1323 if (m_multiple) { 1339 if (m_multiple) {
1324 // Only extend selection if there is something selected. 1340 // Only extend selection if there is something selected.
1325 if (m_activeSelectionAnchorIndex < 0) 1341 if (m_activeSelectionAnchorIndex < 0)
1326 return; 1342 return;
1327 1343
1328 setActiveSelectionEndIndex(listIndex); 1344 setActiveSelectionEndIndex(listIndex);
1329 updateListBoxSelection(false); 1345 updateListBoxSelection(false);
1330 } else { 1346 } else {
1331 setActiveSelectionAnchorIndex(listIndex); 1347 setActiveSelectionAnchorIndex(listIndex);
1332 setActiveSelectionEndIndex(listIndex); 1348 setActiveSelectionEndIndex(listIndex);
1333 updateListBoxSelection(true); 1349 updateListBoxSelection(true);
1334 } 1350 }
1335 } 1351 }
1336 event->setDefaultHandled(); 1352 event->setDefaultHandled();
1337 } 1353 }
1338 } else if (event->type() == eventNames().mouseupEvent && event->isMouseEvent () && static_cast<MouseEvent*>(event)->button() == LeftButton && document()->fra me()->eventHandler()->autoscrollRenderer() != renderer()) { 1354 } else if (event->type() == eventNames().mouseupEvent && event->isMouseEvent () && static_cast<MouseEvent*>(event)->button() == LeftButton)
1339 // This makes sure we fire dispatchFormControlChangeEvent for a single
1340 // click. For drag selection, onChange will fire when the autoscroll
1341 // timer stops.
1342 listBoxOnChange(); 1355 listBoxOnChange();
1343 } else if (event->type() == eventNames().keydownEvent) { 1356 else if (event->type() == eventNames().keydownEvent) {
1344 if (!event->isKeyboardEvent()) 1357 if (!event->isKeyboardEvent())
1345 return; 1358 return;
1346 const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIde ntifier(); 1359 const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIde ntifier();
1347 1360
1348 bool handled = false; 1361 bool handled = false;
1349 int endIndex = 0; 1362 int endIndex = 0;
1350 if (m_activeSelectionEndIndex < 0) { 1363 if (m_activeSelectionEndIndex < 0) {
1351 // Initialize the end index 1364 // Initialize the end index
1352 if (keyIdentifier == "Down" || keyIdentifier == "PageDown") { 1365 if (keyIdentifier == "Down" || keyIdentifier == "PageDown") {
1353 int startIndex = lastSelectedListIndex(); 1366 int startIndex = lastSelectedListIndex();
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1407 m_activeSelectionState = true; 1420 m_activeSelectionState = true;
1408 // If the anchor is unitialized, or if we're going to deselect all 1421 // If the anchor is unitialized, or if we're going to deselect all
1409 // other options, then set the anchor index equal to the end index. 1422 // other options, then set the anchor index equal to the end index.
1410 bool deselectOthers = !m_multiple || (!static_cast<KeyboardEvent*>(e vent)->shiftKey() && selectNewItem); 1423 bool deselectOthers = !m_multiple || (!static_cast<KeyboardEvent*>(e vent)->shiftKey() && selectNewItem);
1411 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { 1424 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
1412 if (deselectOthers) 1425 if (deselectOthers)
1413 deselectItemsWithoutValidation(); 1426 deselectItemsWithoutValidation();
1414 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); 1427 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
1415 } 1428 }
1416 1429
1417 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd ex); 1430 listItems[endIndex]->scrollIntoViewIfNeeded(false);
1418 if (selectNewItem) { 1431 if (selectNewItem) {
1419 updateListBoxSelection(deselectOthers); 1432 updateListBoxSelection(deselectOthers);
1420 listBoxOnChange(); 1433 listBoxOnChange();
1421 } else 1434 } else
1422 scrollToSelection(); 1435 scrollToSelection();
1423 1436
1424 event->setDefaultHandled(); 1437 event->setDefaultHandled();
1425 } 1438 }
1426 } else if (event->type() == eventNames().keypressEvent) { 1439 } else if (event->type() == eventNames().keypressEvent) {
1427 if (!event->isKeyboardEvent()) 1440 if (!event->isKeyboardEvent())
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1554 1567
1555 const Vector<HTMLElement*>& items = listItems(); 1568 const Vector<HTMLElement*>& items = listItems();
1556 for (unsigned i = 0; i < items.size(); ++i) { 1569 for (unsigned i = 0; i < items.size(); ++i) {
1557 if (items[i]->hasTagName(optionTag)) 1570 if (items[i]->hasTagName(optionTag))
1558 ++options; 1571 ++options;
1559 } 1572 }
1560 1573
1561 return options; 1574 return options;
1562 } 1575 }
1563 1576
1577 void HTMLSelectElement::dispatchFormControlChangeEvent()
1578 {
1579 if (renderer() && renderer()->isListBox()) {
1580 AXObjectCache* cache = document()->existingAXObjectCache();
1581 if (cache)
1582 cache->selectedChildrenChanged(renderer());
1583 }
1584 HTMLFormControlElement::dispatchChangeEvent();
1585 }
1586
1564 } // namespace 1587 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698