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

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

Issue 347773002: Implement select listbox using shadow DOM (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fixed accessibility Created 6 years, 5 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 | Annotate | Revision Log
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 21 matching lines...) Expand all
32 #include "bindings/core/v8/ExceptionState.h" 32 #include "bindings/core/v8/ExceptionState.h"
33 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 33 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
34 #include "core/HTMLNames.h" 34 #include "core/HTMLNames.h"
35 #include "core/accessibility/AXObjectCache.h" 35 #include "core/accessibility/AXObjectCache.h"
36 #include "core/dom/Attribute.h" 36 #include "core/dom/Attribute.h"
37 #include "core/dom/ElementTraversal.h" 37 #include "core/dom/ElementTraversal.h"
38 #include "core/dom/NodeTraversal.h" 38 #include "core/dom/NodeTraversal.h"
39 #include "core/events/GestureEvent.h" 39 #include "core/events/GestureEvent.h"
40 #include "core/events/KeyboardEvent.h" 40 #include "core/events/KeyboardEvent.h"
41 #include "core/events/MouseEvent.h" 41 #include "core/events/MouseEvent.h"
42 #include "core/frame/FrameView.h"
42 #include "core/frame/LocalFrame.h" 43 #include "core/frame/LocalFrame.h"
43 #include "core/html/FormDataList.h" 44 #include "core/html/FormDataList.h"
44 #include "core/html/HTMLFormElement.h" 45 #include "core/html/HTMLFormElement.h"
46 #include "core/html/HTMLOptGroupElement.h"
45 #include "core/html/HTMLOptionElement.h" 47 #include "core/html/HTMLOptionElement.h"
46 #include "core/html/forms/FormController.h" 48 #include "core/html/forms/FormController.h"
49 #include "core/page/AutoscrollController.h"
47 #include "core/page/EventHandler.h" 50 #include "core/page/EventHandler.h"
51 #include "core/page/Page.h"
48 #include "core/page/SpatialNavigation.h" 52 #include "core/page/SpatialNavigation.h"
53 #include "core/rendering/HitTestRequest.h"
54 #include "core/rendering/HitTestResult.h"
49 #include "core/rendering/RenderListBox.h" 55 #include "core/rendering/RenderListBox.h"
50 #include "core/rendering/RenderMenuList.h" 56 #include "core/rendering/RenderMenuList.h"
51 #include "core/rendering/RenderTheme.h" 57 #include "core/rendering/RenderTheme.h"
58 #include "core/rendering/RenderView.h"
52 #include "platform/PlatformMouseEvent.h" 59 #include "platform/PlatformMouseEvent.h"
53 #include "platform/text/PlatformLocale.h" 60 #include "platform/text/PlatformLocale.h"
54 61
55 using namespace WTF::Unicode; 62 using namespace WTF::Unicode;
56 63
57 namespace WebCore { 64 namespace WebCore {
58 65
59 using namespace HTMLNames; 66 using namespace HTMLNames;
60 67
61 // Upper limit agreed upon with representatives of Opera and Mozilla. 68 // Upper limit agreed upon with representatives of Opera and Mozilla.
(...skipping 11 matching lines...) Expand all
73 , m_activeSelectionState(false) 80 , m_activeSelectionState(false)
74 , m_shouldRecalcListItems(false) 81 , m_shouldRecalcListItems(false)
75 , m_suggestedIndex(-1) 82 , m_suggestedIndex(-1)
76 { 83 {
77 ScriptWrappable::init(this); 84 ScriptWrappable::init(this);
78 setHasCustomStyleCallbacks(); 85 setHasCustomStyleCallbacks();
79 } 86 }
80 87
81 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument) 88 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument)
82 { 89 {
83 return adoptRefWillBeNoop(new HTMLSelectElement(document, 0)); 90 RefPtrWillBeRawPtr<HTMLSelectElement> select = adoptRefWillBeNoop(new HTMLSe lectElement(document, 0));
91 select->ensureUserAgentShadowRoot();
92 return select.release();
84 } 93 }
85 94
86 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument, HTMLFormElement* form) 95 PassRefPtrWillBeRawPtr<HTMLSelectElement> HTMLSelectElement::create(Document& do cument, HTMLFormElement* form)
87 { 96 {
88 return adoptRefWillBeNoop(new HTMLSelectElement(document, form)); 97 RefPtrWillBeRawPtr<HTMLSelectElement> select = adoptRefWillBeNoop(new HTMLSe lectElement(document, form));
98 select->ensureUserAgentShadowRoot();
99 return select.release();
89 } 100 }
90 101
91 const AtomicString& HTMLSelectElement::formControlType() const 102 const AtomicString& HTMLSelectElement::formControlType() const
92 { 103 {
93 DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple", AtomicString::ConstructFromLiteral)); 104 DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple", AtomicString::ConstructFromLiteral));
94 DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicStri ng::ConstructFromLiteral)); 105 DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one", AtomicStri ng::ConstructFromLiteral));
95 return m_multiple ? selectMultiple : selectOne; 106 return m_multiple ? selectMultiple : selectOne;
96 } 107 }
97 108
98 void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeN ow, bool allowMultipleSelection) 109 void HTMLSelectElement::optionSelectedByUser(int optionIndex, bool fireOnChangeN ow, bool allowMultipleSelection)
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 // Valid means that it is enabled and an option element. 527 // Valid means that it is enabled and an option element.
517 int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, in t skip) const 528 int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, in t skip) const
518 { 529 {
519 ASSERT(direction == -1 || direction == 1); 530 ASSERT(direction == -1 || direction == 1);
520 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); 531 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems();
521 int lastGoodIndex = listIndex; 532 int lastGoodIndex = listIndex;
522 int size = listItems.size(); 533 int size = listItems.size();
523 for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex + = direction) { 534 for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex + = direction) {
524 --skip; 535 --skip;
525 HTMLElement* element = listItems[listIndex]; 536 HTMLElement* element = listItems[listIndex];
526 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) 537 if (!isHTMLOptionElement(*element))
538 continue;
539 if (element->isDisabledFormControl())
540 continue;
541 if (!usesMenuList() && !element->renderer())
527 continue; 542 continue;
528 lastGoodIndex = listIndex; 543 lastGoodIndex = listIndex;
529 if (skip <= 0) 544 if (skip <= 0)
530 break; 545 break;
531 } 546 }
532 return lastGoodIndex; 547 return lastGoodIndex;
533 } 548 }
534 549
535 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const 550 int HTMLSelectElement::nextSelectableListIndex(int startIndex) const
536 { 551 {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 634
620 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 635 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
621 for (unsigned i = 0; i < items.size(); ++i) { 636 for (unsigned i = 0; i < items.size(); ++i) {
622 HTMLElement* element = items[i]; 637 HTMLElement* element = items[i];
623 m_cachedStateForActiveSelection.append(isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected()); 638 m_cachedStateForActiveSelection.append(isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected());
624 } 639 }
625 } 640 }
626 641
627 void HTMLSelectElement::setActiveSelectionEndIndex(int index) 642 void HTMLSelectElement::setActiveSelectionEndIndex(int index)
628 { 643 {
644 if (index == m_activeSelectionEndIndex)
645 return;
629 m_activeSelectionEndIndex = index; 646 m_activeSelectionEndIndex = index;
647 setNeedsStyleRecalc(SubtreeStyleChange);
630 } 648 }
631 649
632 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions) 650 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
633 { 651 {
634 ASSERT(renderer() && (renderer()->isListBox() || m_multiple)); 652 ASSERT(renderer() && (renderer()->isListBox() || m_multiple));
635 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0); 653 ASSERT(!listItems().size() || m_activeSelectionAnchorIndex >= 0);
636 654
637 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd Index); 655 unsigned start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEnd Index);
638 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn dex); 656 unsigned end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIn dex);
639 657
640 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 658 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
641 for (unsigned i = 0; i < items.size(); ++i) { 659 for (unsigned i = 0; i < items.size(); ++i) {
642 HTMLElement* element = items[i]; 660 HTMLElement* element = items[i];
643 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || toHTMLOptionElement(element)->isDisplayNone()) 661 if (!isHTMLOptionElement(*element) || toHTMLOptionElement(element)->isDi sabledFormControl() || !toHTMLOptionElement(element)->renderer())
644 continue; 662 continue;
645 663
646 if (i >= start && i <= end) 664 if (i >= start && i <= end)
647 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat e); 665 toHTMLOptionElement(element)->setSelectedState(m_activeSelectionStat e);
648 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si ze()) 666 else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.si ze())
649 toHTMLOptionElement(element)->setSelectedState(false); 667 toHTMLOptionElement(element)->setSelectedState(false);
650 else 668 else
651 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv eSelection[i]); 669 toHTMLOptionElement(element)->setSelectedState(m_cachedStateForActiv eSelection[i]);
652 } 670 }
653 671
672 setNeedsValidityCheck();
654 scrollToSelection(); 673 scrollToSelection();
655 setNeedsValidityCheck();
656 notifyFormStateChanged(); 674 notifyFormStateChanged();
657 } 675 }
658 676
659 void HTMLSelectElement::listBoxOnChange() 677 void HTMLSelectElement::listBoxOnChange()
660 { 678 {
661 ASSERT(!usesMenuList() || m_multiple); 679 ASSERT(!usesMenuList() || m_multiple);
662 680
663 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 681 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
664 682
665 // If the cached selection list is empty, or the size has changed, then fire 683 // If the cached selection list is empty, or the size has changed, then fire
(...skipping 30 matching lines...) Expand all
696 m_lastOnChangeIndex = selected; 714 m_lastOnChangeIndex = selected;
697 m_isProcessingUserDrivenChange = false; 715 m_isProcessingUserDrivenChange = false;
698 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this); 716 RefPtrWillBeRawPtr<HTMLSelectElement> protector(this);
699 dispatchInputEvent(); 717 dispatchInputEvent();
700 dispatchFormControlChangeEvent(); 718 dispatchFormControlChangeEvent();
701 } 719 }
702 } 720 }
703 721
704 void HTMLSelectElement::scrollToSelection() 722 void HTMLSelectElement::scrollToSelection()
705 { 723 {
724 if (!isFinishedParsingChildren())
725 return;
706 if (usesMenuList()) 726 if (usesMenuList())
707 return; 727 return;
708 728 scrollTo(activeSelectionEndListIndex());
709 if (RenderObject* renderer = this->renderer()) 729 if (AXObjectCache* cache = document().existingAXObjectCache())
710 toRenderListBox(renderer)->selectionChanged(); 730 cache->selectedChildrenChanged(this);
711 } 731 }
712 732
713 void HTMLSelectElement::setOptionsChangedOnRenderer() 733 void HTMLSelectElement::setOptionsChangedOnRenderer()
714 { 734 {
715 if (RenderObject* renderer = this->renderer()) { 735 if (RenderObject* renderer = this->renderer()) {
716 if (usesMenuList()) 736 if (usesMenuList())
717 toRenderMenuList(renderer)->setOptionsChanged(true); 737 toRenderMenuList(renderer)->setOptionsChanged(true);
718 else
719 toRenderListBox(renderer)->setOptionsChanged(true);
720 } 738 }
721 } 739 }
722 740
723 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const 741 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& HTMLSelectElement::lis tItems() const
724 { 742 {
725 if (m_shouldRecalcListItems) 743 if (m_shouldRecalcListItems)
726 recalcListItems(); 744 recalcListItems();
727 else { 745 else {
728 #if ASSERT_ENABLED 746 #if ASSERT_ENABLED
729 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems; 747 WillBeHeapVector<RawPtrWillBeMember<HTMLElement> > items = m_listItems;
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 { 869 {
852 return m_suggestedIndex; 870 return m_suggestedIndex;
853 } 871 }
854 872
855 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex) 873 void HTMLSelectElement::setSuggestedIndex(int suggestedIndex)
856 { 874 {
857 m_suggestedIndex = suggestedIndex; 875 m_suggestedIndex = suggestedIndex;
858 876
859 if (RenderObject* renderer = this->renderer()) { 877 if (RenderObject* renderer = this->renderer()) {
860 renderer->updateFromElement(); 878 renderer->updateFromElement();
861 if (renderer->isListBox()) 879 scrollTo(suggestedIndex);
862 toRenderListBox(renderer)->scrollToRevealElementAtListIndex(suggeste dIndex);
863 } 880 }
864 } 881 }
865 882
883 void HTMLSelectElement::scrollTo(int listIndex)
884 {
885 if (listIndex < 0)
886 return;
887 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
888 int listSize = static_cast<int>(items.size());
889 if (listIndex >= listSize)
890 return;
891 items[listIndex]->scrollIntoViewIfNeeded(false);
892 }
893
866 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected) 894 void HTMLSelectElement::optionSelectionStateChanged(HTMLOptionElement* option, b ool optionIsSelected)
867 { 895 {
868 ASSERT(option->ownerSelectElement() == this); 896 ASSERT(option->ownerSelectElement() == this);
869 if (optionIsSelected) 897 if (optionIsSelected)
870 selectOption(option->index()); 898 selectOption(option->index());
871 else if (!usesMenuList() || multiple()) 899 else if (!usesMenuList() || multiple())
872 selectOption(-1); 900 selectOption(-1);
873 else 901 else
874 selectOption(nextSelectableListIndex(-1)); 902 selectOption(nextSelectableListIndex(-1));
875 } 903 }
876 904
905 void HTMLSelectElement::optionRemoved(const HTMLOptionElement& option)
906 {
907 if (m_activeSelectionAnchorIndex < 0 && m_activeSelectionEndIndex < 0)
908 return;
909 int listIndex = optionToListIndex(option.index());
910 if (listIndex <= m_activeSelectionAnchorIndex)
911 m_activeSelectionAnchorIndex--;
912 if (listIndex <= m_activeSelectionEndIndex)
913 m_activeSelectionEndIndex--;
914 }
915
877 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags) 916 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
878 { 917 {
879 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions); 918 bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions);
880 919
881 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 920 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
882 int listIndex = optionToListIndex(optionIndex); 921 int listIndex = optionToListIndex(optionIndex);
883 922
884 HTMLElement* element = 0; 923 HTMLElement* element = 0;
885 if (listIndex >= 0) { 924 if (listIndex >= 0) {
886 element = items[listIndex]; 925 element = items[listIndex];
(...skipping 15 matching lines...) Expand all
902 941
903 scrollToSelection(); 942 scrollToSelection();
904 943
905 setNeedsValidityCheck(); 944 setNeedsValidityCheck();
906 945
907 if (usesMenuList()) { 946 if (usesMenuList()) {
908 m_isProcessingUserDrivenChange = flags & UserDriven; 947 m_isProcessingUserDrivenChange = flags & UserDriven;
909 if (flags & DispatchInputAndChangeEvent) 948 if (flags & DispatchInputAndChangeEvent)
910 dispatchInputAndChangeEventForMenuList(); 949 dispatchInputAndChangeEventForMenuList();
911 if (RenderObject* renderer = this->renderer()) { 950 if (RenderObject* renderer = this->renderer()) {
912 if (usesMenuList()) 951 if (usesMenuList()) {
913 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex); 952 toRenderMenuList(renderer)->didSetSelectedIndex(listIndex);
914 else if (renderer->isListBox()) 953 } else if (renderer->isListBox()) {
915 toRenderListBox(renderer)->selectionChanged(); 954 if (AXObjectCache* cache = document().existingAXObjectCache())
955 cache->selectedChildrenChanged(this);
956 }
916 } 957 }
917 } 958 }
918 959
919 notifyFormStateChanged(); 960 notifyFormStateChanged();
920 } 961 }
921 962
922 int HTMLSelectElement::optionToListIndex(int optionIndex) const 963 int HTMLSelectElement::optionToListIndex(int optionIndex) const
923 { 964 {
924 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 965 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
925 int listSize = static_cast<int>(items.size()); 966 int listSize = static_cast<int>(items.size());
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1046 startIndex = foundIndex + 1; 1087 startIndex = foundIndex + 1;
1047 } 1088 }
1048 } 1089 }
1049 1090
1050 setOptionsChangedOnRenderer(); 1091 setOptionsChangedOnRenderer();
1051 setNeedsValidityCheck(); 1092 setNeedsValidityCheck();
1052 } 1093 }
1053 1094
1054 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value) 1095 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value)
1055 { 1096 {
1056 bool oldUsesMenuList = usesMenuList();
1057 m_multiple = !value.isNull(); 1097 m_multiple = !value.isNull();
1058 setNeedsValidityCheck(); 1098 setNeedsValidityCheck();
1059 if (oldUsesMenuList != usesMenuList()) 1099
1060 lazyReattachIfAttached(); 1100 lazyReattachIfAttached();
1061 } 1101 }
1062 1102
1063 bool HTMLSelectElement::appendFormData(FormDataList& list, bool) 1103 bool HTMLSelectElement::appendFormData(FormDataList& list, bool)
1064 { 1104 {
1065 const AtomicString& name = this->name(); 1105 const AtomicString& name = this->name();
1066 if (name.isEmpty()) 1106 if (name.isEmpty())
1067 return false; 1107 return false;
1068 1108
1069 bool successful = false; 1109 bool successful = false;
1070 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( ); 1110 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = listItems( );
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
1328 // we're doing a single selection, or a multiple selection (using cmd or 1368 // we're doing a single selection, or a multiple selection (using cmd or
1329 // ctrl), then initialize the anchor index to the listIndex that just got 1369 // ctrl), then initialize the anchor index to the listIndex that just got
1330 // clicked. 1370 // clicked.
1331 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) 1371 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect)
1332 setActiveSelectionAnchorIndex(listIndex); 1372 setActiveSelectionAnchorIndex(listIndex);
1333 1373
1334 setActiveSelectionEndIndex(listIndex); 1374 setActiveSelectionEndIndex(listIndex);
1335 updateListBoxSelection(!multiSelect); 1375 updateListBoxSelection(!multiSelect);
1336 } 1376 }
1337 1377
1378 int HTMLSelectElement::listIndexForEventTargetOption(const Event& event)
1379 {
1380 Node* targetNode = event.target()->toNode();
1381 if (!targetNode || !isHTMLOptionElement(*targetNode))
1382 return -1;
1383 return listIndexForOption(toHTMLOptionElement(*targetNode));
1384 }
1385
1386 int HTMLSelectElement::listIndexForOption(const HTMLOptionElement& option)
1387 {
1388 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = this->list Items();
1389 size_t length = items.size();
1390 for (size_t i = 0; i < length; ++i) {
1391 if (items[i] == &option)
1392 return i;
1393 }
1394 return -1;
1395 }
1396
1397 AutoscrollController* HTMLSelectElement::autoscrollController() const
1398 {
1399 if (Page* page = document().page())
1400 return &page->autoscrollController();
1401 return 0;
1402 }
1403
1404 void HTMLSelectElement::handleMouseRelease()
1405 {
1406 // We didn't start this click/drag on any options.
1407 if (m_lastOnChangeSelection.isEmpty())
1408 return;
1409 listBoxOnChange();
1410 }
1411
1338 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) 1412 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
1339 { 1413 {
1340 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems(); 1414 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this-> listItems();
1341 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) { 1415 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) {
1342 focus(); 1416 focus();
1343 // Calling focus() may cause us to lose our renderer or change the rende r type, in which case do not want to handle the event. 1417 // Calling focus() may cause us to lose our renderer or change the rende r type, in which case do not want to handle the event.
1344 if (!renderer() || !renderer()->isListBox()) 1418 if (!renderer() || !renderer()->isListBox())
1345 return; 1419 return;
1346 1420
1347 // Convert to coords relative to the list box if needed. 1421 // Convert to coords relative to the list box if needed.
1348 GestureEvent& gestureEvent = toGestureEvent(*event); 1422 GestureEvent& gestureEvent = toGestureEvent(*event);
1349 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(gestu reEvent.absoluteLocation(), UseTransforms)); 1423 int listIndex = listIndexForEventTargetOption(gestureEvent);
1350 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1351 if (listIndex >= 0) { 1424 if (listIndex >= 0) {
1352 if (!isDisabledFormControl()) 1425 if (!isDisabledFormControl())
1353 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); 1426 updateSelectedState(listIndex, true, gestureEvent.shiftKey());
1354 event->setDefaultHandled(); 1427 event->setDefaultHandled();
1355 } 1428 }
1356 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) { 1429 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent () && toMouseEvent(event)->button() == LeftButton) {
1357 focus(); 1430 focus();
1358 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event. 1431 // Calling focus() may cause us to lose our renderer, in which case do n ot want to handle the event.
1359 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) 1432 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl())
1360 return; 1433 return;
1361 1434
1435 if (Page* page = document().page())
1436 page->autoscrollController().startAutoscrollForSelection(renderer()) ;
1437
1362 // Convert to coords relative to the list box if needed. 1438 // Convert to coords relative to the list box if needed.
1363 MouseEvent* mouseEvent = toMouseEvent(event); 1439 MouseEvent* mouseEvent = toMouseEvent(event);
1364 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms)); 1440 int listIndex = listIndexForEventTargetOption(*mouseEvent);
1365 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1366 if (listIndex >= 0) { 1441 if (listIndex >= 0) {
1367 if (!isDisabledFormControl()) { 1442 if (!isDisabledFormControl()) {
1368 #if OS(MACOSX) 1443 #if OS(MACOSX)
1369 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey()); 1444 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent ->shiftKey());
1370 #else 1445 #else
1371 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey()); 1446 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent ->shiftKey());
1372 #endif 1447 #endif
1373 } 1448 }
1374 if (LocalFrame* frame = document().frame()) 1449 if (LocalFrame* frame = document().frame())
1375 frame->eventHandler().setMouseDownMayStartAutoscroll(); 1450 frame->eventHandler().setMouseDownMayStartAutoscroll();
1376 1451
1377 event->setDefaultHandled(); 1452 event->setDefaultHandled();
1378 } 1453 }
1379 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent () && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { 1454 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent ()) {
1380 MouseEvent* mouseEvent = toMouseEvent(event); 1455 MouseEvent* mouseEvent = toMouseEvent(event);
1381 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) 1456 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown())
1382 return; 1457 return;
1383 1458 int listIndex = listIndexForEventTargetOption(*mouseEvent);
1384 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse Event->absoluteLocation(), UseTransforms));
1385 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize (localOffset));
1386 if (listIndex >= 0) { 1459 if (listIndex >= 0) {
1387 if (!isDisabledFormControl()) { 1460 if (!isDisabledFormControl()) {
1388 if (m_multiple) { 1461 if (m_multiple) {
1389 // Only extend selection if there is something selected. 1462 // Only extend selection if there is something selected.
1390 if (m_activeSelectionAnchorIndex < 0) 1463 if (m_activeSelectionAnchorIndex < 0)
1391 return; 1464 return;
1392 1465
1393 setActiveSelectionEndIndex(listIndex); 1466 setActiveSelectionEndIndex(listIndex);
1394 updateListBoxSelection(false); 1467 updateListBoxSelection(false);
1395 } else { 1468 } else {
1396 setActiveSelectionAnchorIndex(listIndex); 1469 setActiveSelectionAnchorIndex(listIndex);
1397 setActiveSelectionEndIndex(listIndex); 1470 setActiveSelectionEndIndex(listIndex);
1398 updateListBoxSelection(true); 1471 updateListBoxSelection(true);
1399 } 1472 }
1400 } 1473 }
1401 } 1474 }
1402 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer() && !toRenderBox(re nderer())->autoscrollInProgress()) { 1475 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton && renderer()) {
1403 // We didn't start this click/drag on any options. 1476 if (document().page() && document().page()->autoscrollController().autos crollInProgress(toRenderBox(renderer())))
1404 if (m_lastOnChangeSelection.isEmpty()) 1477 document().page()->autoscrollController().stopAutoscroll();
1405 return; 1478 else
1406 listBoxOnChange(); 1479 handleMouseRelease();
1407 } else if (event->type() == EventTypeNames::keydown) { 1480 } else if (event->type() == EventTypeNames::keydown) {
1408 if (!event->isKeyboardEvent()) 1481 if (!event->isKeyboardEvent())
1409 return; 1482 return;
1410 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); 1483 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier();
1411 1484
1412 bool handled = false; 1485 bool handled = false;
1413 int endIndex = 0; 1486 int endIndex = 0;
1414 if (m_activeSelectionEndIndex < 0) { 1487 if (m_activeSelectionEndIndex < 0) {
1415 // Initialize the end index 1488 // Initialize the end index
1416 if (keyIdentifier == "Down" || keyIdentifier == "PageDown") { 1489 if (keyIdentifier == "Down" || keyIdentifier == "PageDown") {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1471 m_activeSelectionState = true; 1544 m_activeSelectionState = true;
1472 // If the anchor is unitialized, or if we're going to deselect all 1545 // If the anchor is unitialized, or if we're going to deselect all
1473 // other options, then set the anchor index equal to the end index. 1546 // other options, then set the anchor index equal to the end index.
1474 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem); 1547 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift Key() && selectNewItem);
1475 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { 1548 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
1476 if (deselectOthers) 1549 if (deselectOthers)
1477 deselectItemsWithoutValidation(); 1550 deselectItemsWithoutValidation();
1478 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); 1551 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
1479 } 1552 }
1480 1553
1481 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd ex); 1554 scrollTo(endIndex);
1482 if (selectNewItem) { 1555 if (selectNewItem) {
1483 updateListBoxSelection(deselectOthers); 1556 updateListBoxSelection(deselectOthers);
1484 listBoxOnChange(); 1557 listBoxOnChange();
1485 } else 1558 } else
1486 scrollToSelection(); 1559 scrollToSelection();
1487 1560
1488 event->setDefaultHandled(); 1561 event->setDefaultHandled();
1489 } 1562 }
1490 } else if (event->type() == EventTypeNames::keypress) { 1563 } else if (event->type() == EventTypeNames::keypress) {
1491 if (!event->isKeyboardEvent()) 1564 if (!event->isKeyboardEvent())
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1622 ++options; 1695 ++options;
1623 } 1696 }
1624 1697
1625 return options; 1698 return options;
1626 } 1699 }
1627 1700
1628 void HTMLSelectElement::finishParsingChildren() 1701 void HTMLSelectElement::finishParsingChildren()
1629 { 1702 {
1630 HTMLFormControlElementWithState::finishParsingChildren(); 1703 HTMLFormControlElementWithState::finishParsingChildren();
1631 updateListItemSelectedStates(); 1704 updateListItemSelectedStates();
1705 scrollToSelection();
1632 } 1706 }
1633 1707
1634 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) 1708 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR awPtr<HTMLOptionElement> value, ExceptionState& exceptionState)
1635 { 1709 {
1636 if (!value) { // undefined or null 1710 if (!value) { // undefined or null
1637 remove(index); 1711 remove(index);
1638 return true; 1712 return true;
1639 } 1713 }
1640 setOption(index, value.get(), exceptionState); 1714 setOption(index, value.get(), exceptionState);
1641 return true; 1715 return true;
(...skipping 15 matching lines...) Expand all
1657 } 1731 }
1658 1732
1659 void HTMLSelectElement::trace(Visitor* visitor) 1733 void HTMLSelectElement::trace(Visitor* visitor)
1660 { 1734 {
1661 #if ENABLE(OILPAN) 1735 #if ENABLE(OILPAN)
1662 visitor->trace(m_listItems); 1736 visitor->trace(m_listItems);
1663 #endif 1737 #endif
1664 HTMLFormControlElementWithState::trace(visitor); 1738 HTMLFormControlElementWithState::trace(visitor);
1665 } 1739 }
1666 1740
1741 void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root)
1742 {
1743 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create( document());
1744 content->setAttribute(selectAttr, "option,optgroup");
1745 root.appendChild(content);
1746 }
1747
1748 HTMLOptionElement* HTMLSelectElement::spatialNavigationFocusedOption()
1749 {
1750 if (!isSpatialNavigationEnabled(document().frame()))
1751 return nullptr;
1752 int focusedIndex = activeSelectionEndListIndex();
1753 if (focusedIndex < 0)
1754 focusedIndex = firstSelectableListIndex();
1755 if (focusedIndex < 0)
1756 return nullptr;
1757 HTMLElement* focused = listItems()[focusedIndex];
1758 return isHTMLOptionElement(focused) ? toHTMLOptionElement(focused) : nullptr ;
1759 }
1760
1667 } // namespace 1761 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698