blob: c84e55e86a794ae4432ec7b07b5dcde361184864 [file] [log] [blame]
/*
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights
* reserved.
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_SELECT_ELEMENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_SELECT_ELEMENT_H_
#include "base/gtest_prod_util.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
#include "third_party/blink/renderer/core/html/forms/html_options_collection.h"
#include "third_party/blink/renderer/core/html/forms/option_list.h"
#include "third_party/blink/renderer/core/html/forms/type_ahead.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class AutoscrollController;
class ExceptionState;
class HTMLHRElement;
class HTMLOptGroupElement;
class HTMLOptionElement;
class HTMLOptionElementOrHTMLOptGroupElement;
class HTMLElementOrLong;
class PopupMenu;
class CORE_EXPORT HTMLSelectElement final
: public HTMLFormControlElementWithState,
private TypeAheadDataSource {
DEFINE_WRAPPERTYPEINFO();
public:
static HTMLSelectElement* Create(Document&);
explicit HTMLSelectElement(Document&);
~HTMLSelectElement() override;
int selectedIndex() const;
void setSelectedIndex(int);
// `listIndex' version of |selectedIndex|.
int SelectedListIndex() const;
// For ValidityState
String validationMessage() const override;
bool ValueMissing() const override;
String DefaultToolTip() const override;
void ResetImpl() override;
unsigned length() const;
void setLength(unsigned, ExceptionState&);
// TODO(tkent): Rename |size| to |Size|. This is not an implementation of
// |size| IDL attribute.
unsigned size() const { return size_; }
bool IsMultiple() const { return is_multiple_; }
bool UsesMenuList() const;
void add(const HTMLOptionElementOrHTMLOptGroupElement&,
const HTMLElementOrLong&,
ExceptionState&);
using Node::remove;
void remove(int index);
String value() const;
void setValue(const String&, bool send_events = false);
String SuggestedValue() const;
void SetSuggestedValue(const String&);
// |options| and |selectedOptions| are not safe to be used in in
// HTMLOptionElement::removedFrom() and insertedInto() because their cache
// is inconsistent in these functions.
HTMLOptionsCollection* options();
HTMLCollection* selectedOptions();
// This is similar to |options| HTMLCollection. But this is safe in
// HTMLOptionElement::removedFrom() and insertedInto().
// OptionList supports only forward iteration.
OptionList GetOptionList() const { return OptionList(*this); }
void OptionElementChildrenChanged(const HTMLOptionElement&);
void InvalidateSelectedItems();
using ListItems = HeapVector<Member<HTMLElement>>;
// We prefer |optionList()| to |listItems()|.
const ListItems& GetListItems() const;
void AccessKeyAction(bool send_mouse_events) override;
void SelectOptionByAccessKey(HTMLOptionElement*);
void SetOption(unsigned index, HTMLOptionElement*, ExceptionState&);
Element* namedItem(const AtomicString& name);
HTMLOptionElement* item(unsigned index);
void ScrollToSelection();
void ScrollToOption(HTMLOptionElement*);
bool CanSelectAll() const;
void SelectAll();
void ListBoxOnChange();
int ActiveSelectionEndListIndex() const;
HTMLOptionElement* ActiveSelectionEnd() const;
void SetActiveSelectionAnchor(HTMLOptionElement*);
void SetActiveSelectionEnd(HTMLOptionElement*);
// For use in the implementation of HTMLOptionElement.
void OptionSelectionStateChanged(HTMLOptionElement*, bool option_is_selected);
void OptionInserted(HTMLOptionElement&, bool option_is_selected);
void OptionRemoved(HTMLOptionElement&);
bool AnonymousIndexedSetter(unsigned, HTMLOptionElement*, ExceptionState&);
void OptGroupInsertedOrRemoved(HTMLOptGroupElement&);
void HrInsertedOrRemoved(HTMLHRElement&);
HTMLOptionElement* SpatialNavigationFocusedOption();
void HandleMouseRelease();
int ListIndexForOption(const HTMLOptionElement&);
// Helper functions for popup menu implementations.
String ItemText(const Element&) const;
bool ItemIsDisplayNone(Element&) const;
// itemComputedStyle() returns nullptr only if the owner Document is not
// active. So, It returns a valid object when we open a popup.
const ComputedStyle* ItemComputedStyle(Element&) const;
// Text starting offset in LTR.
LayoutUnit ClientPaddingLeft() const;
// Text starting offset in RTL.
LayoutUnit ClientPaddingRight() const;
void SelectOptionByPopup(int list_index);
void SelectMultipleOptionsByPopup(const Vector<int>& list_indices);
// A popup is canceled when the popup was hidden without selecting an item.
void PopupDidCancel();
// Provisional selection is a selection made using arrow keys or type ahead.
void ProvisionalSelectionChanged(unsigned);
void PopupDidHide();
bool PopupIsVisible() const { return popup_is_visible_; }
HTMLOptionElement* OptionToBeShown() const;
void ShowPopup();
void HidePopup();
PopupMenu* Popup() const { return popup_.Get(); }
void DidMutateSubtree();
void ResetTypeAheadSessionForTesting();
// Used for slot assignment.
static bool CanAssignToSelectSlot(const Node&);
bool HasNonInBodyInsertionMode() const override { return true; }
void Trace(blink::Visitor*) override;
void CloneNonAttributePropertiesFrom(const Element&,
CloneChildrenFlag) override;
private:
const AtomicString& FormControlType() const override;
bool MayTriggerVirtualKeyboard() const override;
void DispatchFocusEvent(
Element* old_focused_element,
WebFocusType,
InputDeviceCapabilities* source_capabilities) override;
void DispatchBlurEvent(Element* new_focused_element,
WebFocusType,
InputDeviceCapabilities* source_capabilities) override;
bool CanStartSelection() const override { return false; }
bool IsEnumeratable() const override { return true; }
bool IsInteractiveContent() const override;
bool SupportsAutofocus() const override;
bool IsLabelable() const override { return true; }
FormControlState SaveFormControlState() const override;
void RestoreFormControlState(const FormControlState&) override;
void ParseAttribute(const AttributeModificationParams&) override;
bool IsPresentationAttribute(const QualifiedName&) const override;
LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
void DidRecalcStyle(StyleRecalcChange) override;
void DetachLayoutTree(const AttachContext& = AttachContext()) override;
void AppendToFormData(FormData&) override;
void DidAddUserAgentShadowRoot(ShadowRoot&) override;
void DefaultEventHandler(Event&) override;
void DispatchInputAndChangeEventForMenuList();
void SetRecalcListItems();
void RecalcListItems() const;
enum ResetReason { kResetReasonSelectedOptionRemoved, kResetReasonOthers };
void ResetToDefaultSelection(ResetReason = kResetReasonOthers);
void TypeAheadFind(const KeyboardEvent&);
void SaveLastSelection();
void SaveListboxActiveSelection();
// Returns the first selected OPTION, or nullptr.
HTMLOptionElement* SelectedOption() const;
bool IsOptionalFormControl() const override {
return !IsRequiredFormControl();
}
bool IsRequiredFormControl() const override;
bool HasPlaceholderLabelOption() const;
enum SelectOptionFlag {
kDeselectOtherOptionsFlag = 1 << 0,
kDispatchInputAndChangeEventFlag = 1 << 1,
kMakeOptionDirtyFlag = 1 << 2,
};
typedef unsigned SelectOptionFlags;
void SelectOption(HTMLOptionElement*, SelectOptionFlags);
bool DeselectItemsWithoutValidation(
HTMLOptionElement* element_to_exclude = nullptr);
void ParseMultipleAttribute(const AtomicString&);
HTMLOptionElement* LastSelectedOption() const;
void UpdateSelectedState(HTMLOptionElement*, bool multi, bool shift);
void MenuListDefaultEventHandler(Event&);
void HandlePopupOpenKeyboardEvent(Event&);
bool ShouldOpenPopupForKeyDownEvent(const KeyboardEvent&);
bool ShouldOpenPopupForKeyPressEvent(const KeyboardEvent&);
void ListBoxDefaultEventHandler(Event&);
void SetOptionsChangedOnLayoutObject();
wtf_size_t SearchOptionsForValue(const String&,
wtf_size_t list_index_start,
wtf_size_t list_index_end) const;
void UpdateListBoxSelection(bool deselect_other_options, bool scroll = true);
void SetIndexToSelectOnCancel(int list_index);
void SetSuggestedOption(HTMLOptionElement*);
// Returns nullptr if listIndex is out of bounds, or it doesn't point an
// HTMLOptionElement.
HTMLOptionElement* OptionAtListIndex(int list_index) const;
enum SkipDirection { kSkipBackwards = -1, kSkipForwards = 1 };
HTMLOptionElement* NextValidOption(int list_index,
SkipDirection,
int skip) const;
HTMLOptionElement* NextSelectableOption(HTMLOptionElement*) const;
HTMLOptionElement* PreviousSelectableOption(HTMLOptionElement*) const;
HTMLOptionElement* FirstSelectableOption() const;
HTMLOptionElement* LastSelectableOption() const;
HTMLOptionElement* NextSelectableOptionPageAway(HTMLOptionElement*,
SkipDirection) const;
HTMLOptionElement* EventTargetOption(const Event&);
AutoscrollController* GetAutoscrollController() const;
void ScrollToOptionTask();
bool AreAuthorShadowsAllowed() const override { return false; }
void FinishParsingChildren() override;
// TypeAheadDataSource functions.
int IndexOfSelectedOption() const override;
int OptionCount() const override;
String OptionAtIndex(int index) const override;
void ObserveTreeMutation();
void UnobserveTreeMutation();
// list_items_ contains HTMLOptionElement, HTMLOptGroupElement, and
// HTMLHRElement objects.
mutable ListItems list_items_;
Vector<bool> last_on_change_selection_;
Vector<bool> cached_state_for_active_selection_;
TypeAhead type_ahead_;
unsigned size_;
Member<HTMLOptionElement> last_on_change_option_;
Member<HTMLOptionElement> active_selection_anchor_;
Member<HTMLOptionElement> active_selection_end_;
Member<HTMLOptionElement> option_to_scroll_to_;
Member<HTMLOptionElement> suggested_option_;
bool is_multiple_;
bool active_selection_state_;
mutable bool should_recalc_list_items_;
bool is_autofilled_by_preview_;
class PopupUpdater;
Member<PopupUpdater> popup_updater_;
Member<PopupMenu> popup_;
int index_to_select_on_cancel_;
bool popup_is_visible_;
FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, FirstSelectableOption);
FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, LastSelectableOption);
FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, NextSelectableOption);
FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, PreviousSelectableOption);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_HTML_SELECT_ELEMENT_H_