/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/HTMLSelectElement.h" #include "mozAutoDocUpdate.h" #include "mozilla/Attributes.h" #include "mozilla/BasicEvents.h" #include "mozilla/EventDispatcher.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/FormData.h" #include "mozilla/dom/HTMLOptGroupElement.h" #include "mozilla/dom/HTMLOptionElement.h" #include "mozilla/dom/HTMLSelectElementBinding.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/MappedDeclarations.h" #include "mozilla/Maybe.h" #include "nsContentCreatorFunctions.h" #include "nsContentList.h" #include "nsContentUtils.h" #include "nsError.h" #include "nsGkAtoms.h" #include "nsComboboxControlFrame.h" #include "mozilla/dom/Document.h" #include "nsIFormControlFrame.h" #include "nsIFrame.h" #include "nsListControlFrame.h" #include "nsISelectControlFrame.h" #include "nsLayoutUtils.h" #include "nsMappedAttributes.h" #include "mozilla/PresState.h" #include "nsServiceManagerUtils.h" #include "nsStyleConsts.h" #include "nsTextNode.h" NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Select) namespace mozilla::dom { //---------------------------------------------------------------------- // // SafeOptionListMutation // SafeOptionListMutation::SafeOptionListMutation(nsIContent* aSelect, nsIContent* aParent, nsIContent* aKid, uint32_t aIndex, bool aNotify) : mSelect(HTMLSelectElement::FromNodeOrNull(aSelect)), mTopLevelMutation(false), mNeedsRebuild(false), mNotify(aNotify) { if (mSelect) { mInitialSelectedOption = mSelect->Item(mSelect->SelectedIndex()); mTopLevelMutation = !mSelect->mMutating; if (mTopLevelMutation) { mSelect->mMutating = true; } else { // This is very unfortunate, but to handle mutation events properly, // option list must be up-to-date before inserting or removing options. // Fortunately this is called only if mutation event listener // adds or removes options. mSelect->RebuildOptionsArray(mNotify); } nsresult rv; if (aKid) { rv = mSelect->WillAddOptions(aKid, aParent, aIndex, mNotify); } else { rv = mSelect->WillRemoveOptions(aParent, aIndex, mNotify); } mNeedsRebuild = NS_FAILED(rv); } } SafeOptionListMutation::~SafeOptionListMutation() { if (mSelect) { if (mNeedsRebuild || (mTopLevelMutation && mGuard.Mutated(1))) { mSelect->RebuildOptionsArray(true); } if (mTopLevelMutation) { mSelect->mMutating = false; } if (mSelect->Item(mSelect->SelectedIndex()) != mInitialSelectedOption) { // We must have triggered the SelectSomething() codepath, which can cause // our validity to change. Unfortunately, our attempt to update validity // in that case may not have worked correctly, because we actually call it // before we have inserted the new