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 21 matching lines...) Expand all Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 ENABLE(ASSERT) | 746 #if ENABLE(ASSERT) |
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 Loading... |
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 Loading... |
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 Loading... |
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 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1310 // we're doing a single selection, or a multiple selection (using cmd or | 1350 // we're doing a single selection, or a multiple selection (using cmd or |
1311 // ctrl), then initialize the anchor index to the listIndex that just got | 1351 // ctrl), then initialize the anchor index to the listIndex that just got |
1312 // clicked. | 1352 // clicked. |
1313 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) | 1353 if (m_activeSelectionAnchorIndex < 0 || !shiftSelect) |
1314 setActiveSelectionAnchorIndex(listIndex); | 1354 setActiveSelectionAnchorIndex(listIndex); |
1315 | 1355 |
1316 setActiveSelectionEndIndex(listIndex); | 1356 setActiveSelectionEndIndex(listIndex); |
1317 updateListBoxSelection(!multiSelect); | 1357 updateListBoxSelection(!multiSelect); |
1318 } | 1358 } |
1319 | 1359 |
| 1360 int HTMLSelectElement::listIndexForEventTargetOption(const Event& event) |
| 1361 { |
| 1362 Node* targetNode = event.target()->toNode(); |
| 1363 if (!targetNode || !isHTMLOptionElement(*targetNode)) |
| 1364 return -1; |
| 1365 return listIndexForOption(toHTMLOptionElement(*targetNode)); |
| 1366 } |
| 1367 |
| 1368 int HTMLSelectElement::listIndexForOption(const HTMLOptionElement& option) |
| 1369 { |
| 1370 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& items = this->list
Items(); |
| 1371 size_t length = items.size(); |
| 1372 for (size_t i = 0; i < length; ++i) { |
| 1373 if (items[i].get() == &option) |
| 1374 return i; |
| 1375 } |
| 1376 return -1; |
| 1377 } |
| 1378 |
| 1379 AutoscrollController* HTMLSelectElement::autoscrollController() const |
| 1380 { |
| 1381 if (Page* page = document().page()) |
| 1382 return &page->autoscrollController(); |
| 1383 return 0; |
| 1384 } |
| 1385 |
| 1386 void HTMLSelectElement::handleMouseRelease() |
| 1387 { |
| 1388 // We didn't start this click/drag on any options. |
| 1389 if (m_lastOnChangeSelection.isEmpty()) |
| 1390 return; |
| 1391 listBoxOnChange(); |
| 1392 } |
| 1393 |
1320 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) | 1394 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) |
1321 { | 1395 { |
1322 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->
listItems(); | 1396 const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->
listItems(); |
1323 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent())
{ | 1397 if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent())
{ |
1324 focus(); | 1398 focus(); |
1325 // 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. | 1399 // 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. |
1326 if (!renderer() || !renderer()->isListBox()) | 1400 if (!renderer() || !renderer()->isListBox()) |
1327 return; | 1401 return; |
1328 | 1402 |
1329 // Convert to coords relative to the list box if needed. | 1403 // Convert to coords relative to the list box if needed. |
1330 GestureEvent& gestureEvent = toGestureEvent(*event); | 1404 GestureEvent& gestureEvent = toGestureEvent(*event); |
1331 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(gestu
reEvent.absoluteLocation(), UseTransforms)); | 1405 int listIndex = listIndexForEventTargetOption(gestureEvent); |
1332 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize
(localOffset)); | |
1333 if (listIndex >= 0) { | 1406 if (listIndex >= 0) { |
1334 if (!isDisabledFormControl()) | 1407 if (!isDisabledFormControl()) |
1335 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); | 1408 updateSelectedState(listIndex, true, gestureEvent.shiftKey()); |
1336 event->setDefaultHandled(); | 1409 event->setDefaultHandled(); |
1337 } | 1410 } |
1338 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent
() && toMouseEvent(event)->button() == LeftButton) { | 1411 } else if (event->type() == EventTypeNames::mousedown && event->isMouseEvent
() && toMouseEvent(event)->button() == LeftButton) { |
1339 focus(); | 1412 focus(); |
1340 // Calling focus() may cause us to lose our renderer, in which case do n
ot want to handle the event. | 1413 // Calling focus() may cause us to lose our renderer, in which case do n
ot want to handle the event. |
1341 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) | 1414 if (!renderer() || !renderer()->isListBox() || isDisabledFormControl()) |
1342 return; | 1415 return; |
1343 | 1416 |
1344 // Convert to coords relative to the list box if needed. | 1417 // Convert to coords relative to the list box if needed. |
1345 MouseEvent* mouseEvent = toMouseEvent(event); | 1418 MouseEvent* mouseEvent = toMouseEvent(event); |
1346 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse
Event->absoluteLocation(), UseTransforms)); | 1419 int listIndex = listIndexForEventTargetOption(*mouseEvent); |
1347 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize
(localOffset)); | |
1348 if (listIndex >= 0) { | 1420 if (listIndex >= 0) { |
1349 if (!isDisabledFormControl()) { | 1421 if (!isDisabledFormControl()) { |
1350 #if OS(MACOSX) | 1422 #if OS(MACOSX) |
1351 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent
->shiftKey()); | 1423 updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent
->shiftKey()); |
1352 #else | 1424 #else |
1353 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent
->shiftKey()); | 1425 updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent
->shiftKey()); |
1354 #endif | 1426 #endif |
1355 } | 1427 } |
1356 if (LocalFrame* frame = document().frame()) | 1428 if (LocalFrame* frame = document().frame()) |
1357 frame->eventHandler().setMouseDownMayStartAutoscroll(); | 1429 frame->eventHandler().setMouseDownMayStartAutoscroll(); |
1358 | 1430 |
1359 event->setDefaultHandled(); | 1431 event->setDefaultHandled(); |
1360 } | 1432 } |
1361 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent
() && !toRenderBox(renderer())->canBeScrolledAndHasScrollableArea()) { | 1433 } else if (event->type() == EventTypeNames::mousemove && event->isMouseEvent
()) { |
1362 MouseEvent* mouseEvent = toMouseEvent(event); | 1434 MouseEvent* mouseEvent = toMouseEvent(event); |
1363 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) | 1435 if (mouseEvent->button() != LeftButton || !mouseEvent->buttonDown()) |
1364 return; | 1436 return; |
1365 | 1437 |
1366 IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouse
Event->absoluteLocation(), UseTransforms)); | 1438 if (Page* page = document().page()) |
1367 int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toIntSize
(localOffset)); | 1439 page->autoscrollController().startAutoscrollForSelection(renderer())
; |
| 1440 |
| 1441 int listIndex = listIndexForEventTargetOption(*mouseEvent); |
1368 if (listIndex >= 0) { | 1442 if (listIndex >= 0) { |
1369 if (!isDisabledFormControl()) { | 1443 if (!isDisabledFormControl()) { |
1370 if (m_multiple) { | 1444 if (m_multiple) { |
1371 // Only extend selection if there is something selected. | 1445 // Only extend selection if there is something selected. |
1372 if (m_activeSelectionAnchorIndex < 0) | 1446 if (m_activeSelectionAnchorIndex < 0) |
1373 return; | 1447 return; |
1374 | 1448 |
1375 setActiveSelectionEndIndex(listIndex); | 1449 setActiveSelectionEndIndex(listIndex); |
1376 updateListBoxSelection(false); | 1450 updateListBoxSelection(false); |
1377 } else { | 1451 } else { |
1378 setActiveSelectionAnchorIndex(listIndex); | 1452 setActiveSelectionAnchorIndex(listIndex); |
1379 setActiveSelectionEndIndex(listIndex); | 1453 setActiveSelectionEndIndex(listIndex); |
1380 updateListBoxSelection(true); | 1454 updateListBoxSelection(true); |
1381 } | 1455 } |
1382 } | 1456 } |
1383 } | 1457 } |
1384 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent()
&& toMouseEvent(event)->button() == LeftButton && renderer() && !toRenderBox(re
nderer())->autoscrollInProgress()) { | 1458 } else if (event->type() == EventTypeNames::mouseup && event->isMouseEvent()
&& toMouseEvent(event)->button() == LeftButton && renderer()) { |
1385 // We didn't start this click/drag on any options. | 1459 if (document().page() && document().page()->autoscrollController().autos
crollInProgress(toRenderBox(renderer()))) |
1386 if (m_lastOnChangeSelection.isEmpty()) | 1460 document().page()->autoscrollController().stopAutoscroll(); |
1387 return; | 1461 else |
1388 listBoxOnChange(); | 1462 handleMouseRelease(); |
1389 } else if (event->type() == EventTypeNames::keydown) { | 1463 } else if (event->type() == EventTypeNames::keydown) { |
1390 if (!event->isKeyboardEvent()) | 1464 if (!event->isKeyboardEvent()) |
1391 return; | 1465 return; |
1392 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); | 1466 const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); |
1393 | 1467 |
1394 bool handled = false; | 1468 bool handled = false; |
1395 int endIndex = 0; | 1469 int endIndex = 0; |
1396 if (m_activeSelectionEndIndex < 0) { | 1470 if (m_activeSelectionEndIndex < 0) { |
1397 // Initialize the end index | 1471 // Initialize the end index |
1398 if (keyIdentifier == "Down" || keyIdentifier == "PageDown") { | 1472 if (keyIdentifier == "Down" || keyIdentifier == "PageDown") { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 m_activeSelectionState = true; | 1527 m_activeSelectionState = true; |
1454 // If the anchor is unitialized, or if we're going to deselect all | 1528 // If the anchor is unitialized, or if we're going to deselect all |
1455 // other options, then set the anchor index equal to the end index. | 1529 // other options, then set the anchor index equal to the end index. |
1456 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift
Key() && selectNewItem); | 1530 bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shift
Key() && selectNewItem); |
1457 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { | 1531 if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { |
1458 if (deselectOthers) | 1532 if (deselectOthers) |
1459 deselectItemsWithoutValidation(); | 1533 deselectItemsWithoutValidation(); |
1460 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); | 1534 setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); |
1461 } | 1535 } |
1462 | 1536 |
1463 toRenderListBox(renderer())->scrollToRevealElementAtListIndex(endInd
ex); | 1537 scrollTo(endIndex); |
1464 if (selectNewItem) { | 1538 if (selectNewItem) { |
1465 updateListBoxSelection(deselectOthers); | 1539 updateListBoxSelection(deselectOthers); |
1466 listBoxOnChange(); | 1540 listBoxOnChange(); |
1467 } else | 1541 } else |
1468 scrollToSelection(); | 1542 scrollToSelection(); |
1469 | 1543 |
1470 event->setDefaultHandled(); | 1544 event->setDefaultHandled(); |
1471 } | 1545 } |
1472 } else if (event->type() == EventTypeNames::keypress) { | 1546 } else if (event->type() == EventTypeNames::keypress) { |
1473 if (!event->isKeyboardEvent()) | 1547 if (!event->isKeyboardEvent()) |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 ++options; | 1678 ++options; |
1605 } | 1679 } |
1606 | 1680 |
1607 return options; | 1681 return options; |
1608 } | 1682 } |
1609 | 1683 |
1610 void HTMLSelectElement::finishParsingChildren() | 1684 void HTMLSelectElement::finishParsingChildren() |
1611 { | 1685 { |
1612 HTMLFormControlElementWithState::finishParsingChildren(); | 1686 HTMLFormControlElementWithState::finishParsingChildren(); |
1613 updateListItemSelectedStates(); | 1687 updateListItemSelectedStates(); |
| 1688 scrollToSelection(); |
1614 } | 1689 } |
1615 | 1690 |
1616 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR
awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) | 1691 bool HTMLSelectElement::anonymousIndexedSetter(unsigned index, PassRefPtrWillBeR
awPtr<HTMLOptionElement> value, ExceptionState& exceptionState) |
1617 { | 1692 { |
1618 if (!value) { // undefined or null | 1693 if (!value) { // undefined or null |
1619 remove(index); | 1694 remove(index); |
1620 return true; | 1695 return true; |
1621 } | 1696 } |
1622 setOption(index, value.get(), exceptionState); | 1697 setOption(index, value.get(), exceptionState); |
1623 return true; | 1698 return true; |
(...skipping 15 matching lines...) Expand all Loading... |
1639 } | 1714 } |
1640 | 1715 |
1641 void HTMLSelectElement::trace(Visitor* visitor) | 1716 void HTMLSelectElement::trace(Visitor* visitor) |
1642 { | 1717 { |
1643 #if ENABLE(OILPAN) | 1718 #if ENABLE(OILPAN) |
1644 visitor->trace(m_listItems); | 1719 visitor->trace(m_listItems); |
1645 #endif | 1720 #endif |
1646 HTMLFormControlElementWithState::trace(visitor); | 1721 HTMLFormControlElementWithState::trace(visitor); |
1647 } | 1722 } |
1648 | 1723 |
| 1724 void HTMLSelectElement::didAddUserAgentShadowRoot(ShadowRoot& root) |
| 1725 { |
| 1726 RefPtrWillBeRawPtr<HTMLContentElement> content = HTMLContentElement::create(
document()); |
| 1727 content->setAttribute(selectAttr, "option,optgroup"); |
| 1728 root.appendChild(content); |
| 1729 } |
| 1730 |
| 1731 HTMLOptionElement* HTMLSelectElement::spatialNavigationFocusedOption() |
| 1732 { |
| 1733 if (!isSpatialNavigationEnabled(document().frame())) |
| 1734 return nullptr; |
| 1735 int focusedIndex = activeSelectionEndListIndex(); |
| 1736 if (focusedIndex < 0) |
| 1737 focusedIndex = firstSelectableListIndex(); |
| 1738 if (focusedIndex < 0) |
| 1739 return nullptr; |
| 1740 HTMLElement* focused = listItems()[focusedIndex]; |
| 1741 return isHTMLOptionElement(focused) ? toHTMLOptionElement(focused) : nullptr
; |
| 1742 } |
| 1743 |
1649 } // namespace | 1744 } // namespace |
OLD | NEW |