1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/EventDispatcher.h"
8 #include "mozilla/Maybe.h"
9 #include "mozilla/dom/HTMLOptGroupElement.h"
10 #include "mozilla/dom/HTMLOptGroupElementBinding.h"
11 #include "mozilla/dom/HTMLSelectElement.h" // SafeOptionListMutation
12 #include "nsGkAtoms.h"
13 #include "nsStyleConsts.h"
15 #include "nsIFormControlFrame.h"
17 NS_IMPL_NS_NEW_HTML_ELEMENT(OptGroup
)
19 namespace mozilla::dom
{
22 * The implementation of <optgroup>
25 HTMLOptGroupElement::HTMLOptGroupElement(
26 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
27 : nsGenericHTMLElement(std::move(aNodeInfo
)) {
28 // We start off enabled
29 AddStatesSilently(ElementState::ENABLED
);
32 HTMLOptGroupElement::~HTMLOptGroupElement() = default;
34 NS_IMPL_ELEMENT_CLONE(HTMLOptGroupElement
)
36 void HTMLOptGroupElement::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
37 aVisitor
.mCanHandle
= false;
39 if (nsIFrame
* frame
= GetPrimaryFrame()) {
40 // FIXME(emilio): This poking at the style of the frame is broken unless we
41 // flush before every event handling, which we don't really want to.
42 if (frame
->StyleUI()->UserInput() == StyleUserInput::None
) {
47 nsGenericHTMLElement::GetEventTargetParent(aVisitor
);
50 Element
* HTMLOptGroupElement::GetSelect() {
51 Element
* parent
= nsINode::GetParentElement();
52 if (!parent
|| !parent
->IsHTMLElement(nsGkAtoms::select
)) {
58 void HTMLOptGroupElement::InsertChildBefore(nsIContent
* aKid
,
59 nsIContent
* aBeforeThis
,
60 bool aNotify
, ErrorResult
& aRv
) {
61 const uint32_t index
=
62 aBeforeThis
? *ComputeIndexOf(aBeforeThis
) : GetChildCount();
63 SafeOptionListMutation
safeMutation(GetSelect(), this, aKid
, index
, aNotify
);
64 nsGenericHTMLElement::InsertChildBefore(aKid
, aBeforeThis
, aNotify
, aRv
);
66 safeMutation
.MutationFailed();
70 void HTMLOptGroupElement::RemoveChildNode(nsIContent
* aKid
, bool aNotify
) {
71 SafeOptionListMutation
safeMutation(GetSelect(), this, nullptr,
72 *ComputeIndexOf(aKid
), aNotify
);
73 nsGenericHTMLElement::RemoveChildNode(aKid
, aNotify
);
76 void HTMLOptGroupElement::AfterSetAttr(int32_t aNameSpaceID
, nsAtom
* aName
,
77 const nsAttrValue
* aValue
,
78 const nsAttrValue
* aOldValue
,
79 nsIPrincipal
* aSubjectPrincipal
,
81 if (aNameSpaceID
== kNameSpaceID_None
&& aName
== nsGkAtoms::disabled
) {
82 ElementState disabledStates
;
84 disabledStates
|= ElementState::DISABLED
;
86 disabledStates
|= ElementState::ENABLED
;
89 ElementState oldDisabledStates
= State() & ElementState::DISABLED_STATES
;
90 ElementState changedStates
= disabledStates
^ oldDisabledStates
;
92 if (!changedStates
.IsEmpty()) {
93 ToggleStates(changedStates
, aNotify
);
95 // All our children <option> have their :disabled state depending on our
96 // disabled attribute. We should make sure their state is updated.
97 for (nsIContent
* child
= nsINode::GetFirstChild(); child
;
98 child
= child
->GetNextSibling()) {
99 if (auto optElement
= HTMLOptionElement::FromNode(child
)) {
100 optElement
->OptGroupDisabledChanged(true);
106 return nsGenericHTMLElement::AfterSetAttr(
107 aNameSpaceID
, aName
, aValue
, aOldValue
, aSubjectPrincipal
, aNotify
);
110 JSObject
* HTMLOptGroupElement::WrapNode(JSContext
* aCx
,
111 JS::Handle
<JSObject
*> aGivenProto
) {
112 return HTMLOptGroupElement_Binding::Wrap(aCx
, this, aGivenProto
);
115 } // namespace mozilla::dom