LCOV - code coverage report
Current view: top level - dom/html - HTMLOptionElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 183 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 37 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "mozilla/dom/HTMLOptionElement.h"
       8             : #include "mozilla/dom/HTMLOptionElementBinding.h"
       9             : #include "mozilla/dom/HTMLSelectElement.h"
      10             : #include "nsIDOMHTMLOptGroupElement.h"
      11             : #include "nsIDOMHTMLFormElement.h"
      12             : #include "nsGkAtoms.h"
      13             : #include "nsStyleConsts.h"
      14             : #include "nsIFormControl.h"
      15             : #include "nsIForm.h"
      16             : #include "nsIDOMNode.h"
      17             : #include "nsIDOMHTMLCollection.h"
      18             : #include "nsISelectControlFrame.h"
      19             : 
      20             : // Notify/query select frame for selected state
      21             : #include "nsIFormControlFrame.h"
      22             : #include "nsIDocument.h"
      23             : #include "nsIDOMHTMLSelectElement.h"
      24             : #include "nsNodeInfoManager.h"
      25             : #include "nsCOMPtr.h"
      26             : #include "mozilla/EventStates.h"
      27             : #include "nsContentCreatorFunctions.h"
      28             : #include "mozAutoDocUpdate.h"
      29             : #include "nsTextNode.h"
      30             : 
      31             : /**
      32             :  * Implementation of <option>
      33             :  */
      34             : 
      35           0 : NS_IMPL_NS_NEW_HTML_ELEMENT(Option)
      36             : 
      37             : namespace mozilla {
      38             : namespace dom {
      39             : 
      40           0 : HTMLOptionElement::HTMLOptionElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
      41             :   : nsGenericHTMLElement(aNodeInfo),
      42             :     mSelectedChanged(false),
      43             :     mIsSelected(false),
      44           0 :     mIsInSetDefaultSelected(false)
      45             : {
      46             :   // We start off enabled
      47           0 :   AddStatesSilently(NS_EVENT_STATE_ENABLED);
      48           0 : }
      49             : 
      50           0 : HTMLOptionElement::~HTMLOptionElement()
      51             : {
      52           0 : }
      53             : 
      54           0 : NS_IMPL_ISUPPORTS_INHERITED(HTMLOptionElement, nsGenericHTMLElement,
      55             :                             nsIDOMHTMLOptionElement)
      56             : 
      57           0 : NS_IMPL_ELEMENT_CLONE(HTMLOptionElement)
      58             : 
      59             : 
      60             : NS_IMETHODIMP
      61           0 : HTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
      62             : {
      63           0 :   NS_IF_ADDREF(*aForm = GetForm());
      64           0 :   return NS_OK;
      65             : }
      66             : 
      67             : mozilla::dom::HTMLFormElement*
      68           0 : HTMLOptionElement::GetForm()
      69             : {
      70           0 :   HTMLSelectElement* selectControl = GetSelect();
      71           0 :   return selectControl ? selectControl->GetForm() : nullptr;
      72             : }
      73             : 
      74             : void
      75           0 : HTMLOptionElement::SetSelectedInternal(bool aValue, bool aNotify)
      76             : {
      77           0 :   mSelectedChanged = true;
      78           0 :   mIsSelected = aValue;
      79             : 
      80             :   // When mIsInSetDefaultSelected is true, the state change will be handled by
      81             :   // SetAttr/UnsetAttr.
      82           0 :   if (!mIsInSetDefaultSelected) {
      83           0 :     UpdateState(aNotify);
      84             :   }
      85           0 : }
      86             : 
      87             : NS_IMETHODIMP
      88           0 : HTMLOptionElement::GetSelected(bool* aValue)
      89             : {
      90           0 :   NS_ENSURE_ARG_POINTER(aValue);
      91           0 :   *aValue = Selected();
      92           0 :   return NS_OK;
      93             : }
      94             : 
      95             : NS_IMETHODIMP
      96           0 : HTMLOptionElement::SetSelected(bool aValue)
      97             : {
      98             :   // Note: The select content obj maintains all the PresState
      99             :   // so defer to it to get the answer
     100           0 :   HTMLSelectElement* selectInt = GetSelect();
     101           0 :   if (selectInt) {
     102           0 :     int32_t index = Index();
     103           0 :     uint32_t mask = HTMLSelectElement::SET_DISABLED | HTMLSelectElement::NOTIFY;
     104           0 :     if (aValue) {
     105           0 :       mask |= HTMLSelectElement::IS_SELECTED;
     106             :     }
     107             : 
     108             :     // This should end up calling SetSelectedInternal
     109           0 :     selectInt->SetOptionsSelectedByIndex(index, index, mask);
     110             :   } else {
     111           0 :     SetSelectedInternal(aValue, true);
     112             :   }
     113             : 
     114           0 :   return NS_OK;
     115             : }
     116             : 
     117           0 : NS_IMPL_BOOL_ATTR(HTMLOptionElement, DefaultSelected, selected)
     118             : // GetText returns a whitespace compressed .textContent value.
     119           0 : NS_IMPL_STRING_ATTR_WITH_FALLBACK(HTMLOptionElement, Label, label, GetText)
     120           0 : NS_IMPL_STRING_ATTR_WITH_FALLBACK(HTMLOptionElement, Value, value, GetText)
     121           0 : NS_IMPL_BOOL_ATTR(HTMLOptionElement, Disabled, disabled)
     122             : 
     123             : NS_IMETHODIMP
     124           0 : HTMLOptionElement::GetIndex(int32_t* aIndex)
     125             : {
     126           0 :   *aIndex = Index();
     127           0 :   return NS_OK;
     128             : }
     129             : 
     130             : int32_t
     131           0 : HTMLOptionElement::Index()
     132             : {
     133             :   static int32_t defaultIndex = 0;
     134             : 
     135             :   // Only select elements can contain a list of options.
     136           0 :   HTMLSelectElement* selectElement = GetSelect();
     137           0 :   if (!selectElement) {
     138           0 :     return defaultIndex;
     139             :   }
     140             : 
     141           0 :   HTMLOptionsCollection* options = selectElement->GetOptions();
     142           0 :   if (!options) {
     143           0 :     return defaultIndex;
     144             :   }
     145             : 
     146           0 :   int32_t index = defaultIndex;
     147           0 :   MOZ_ALWAYS_SUCCEEDS(options->GetOptionIndex(this, 0, true, &index));
     148           0 :   return index;
     149             : }
     150             : 
     151             : bool
     152           0 : HTMLOptionElement::Selected() const
     153             : {
     154           0 :   return mIsSelected;
     155             : }
     156             : 
     157             : bool
     158           0 : HTMLOptionElement::DefaultSelected() const
     159             : {
     160           0 :   return HasAttr(kNameSpaceID_None, nsGkAtoms::selected);
     161             : }
     162             : 
     163             : nsChangeHint
     164           0 : HTMLOptionElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
     165             :                                           int32_t aModType) const
     166             : {
     167             :   nsChangeHint retval =
     168           0 :       nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
     169             : 
     170           0 :   if (aAttribute == nsGkAtoms::label ||
     171           0 :       aAttribute == nsGkAtoms::text) {
     172           0 :     retval |= NS_STYLE_HINT_REFLOW;
     173             :   }
     174           0 :   return retval;
     175             : }
     176             : 
     177             : nsresult
     178           0 : HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
     179             :                                  const nsAttrValueOrString* aValue,
     180             :                                  bool aNotify)
     181             : {
     182           0 :   nsresult rv = nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName,
     183           0 :                                                     aValue, aNotify);
     184           0 :   NS_ENSURE_SUCCESS(rv, rv);
     185             : 
     186           0 :   if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::selected ||
     187           0 :       mSelectedChanged) {
     188           0 :     return NS_OK;
     189             :   }
     190             : 
     191             :   // We just changed out selected state (since we look at the "selected"
     192             :   // attribute when mSelectedChanged is false).  Let's tell our select about
     193             :   // it.
     194           0 :   HTMLSelectElement* selectInt = GetSelect();
     195           0 :   if (!selectInt) {
     196             :     // If option is a child of select, SetOptionsSelectedByIndex will set
     197             :     // mIsSelected if needed.
     198           0 :     mIsSelected = aValue;
     199           0 :     return NS_OK;
     200             :   }
     201             : 
     202           0 :   NS_ASSERTION(!mSelectedChanged, "Shouldn't be here");
     203             : 
     204           0 :   bool inSetDefaultSelected = mIsInSetDefaultSelected;
     205           0 :   mIsInSetDefaultSelected = true;
     206             : 
     207           0 :   int32_t index = Index();
     208           0 :   uint32_t mask = HTMLSelectElement::SET_DISABLED;
     209           0 :   if (aValue) {
     210           0 :     mask |= HTMLSelectElement::IS_SELECTED;
     211             :   }
     212             : 
     213           0 :   if (aNotify) {
     214           0 :     mask |= HTMLSelectElement::NOTIFY;
     215             :   }
     216             : 
     217             :   // This can end up calling SetSelectedInternal if our selected state needs to
     218             :   // change, which we will allow to take effect so that parts of
     219             :   // SetOptionsSelectedByIndex that might depend on it working don't get
     220             :   // confused.
     221           0 :   selectInt->SetOptionsSelectedByIndex(index, index, mask);
     222             : 
     223             :   // Now reset our members; when we finish the attr set we'll end up with the
     224             :   // rigt selected state.
     225           0 :   mIsInSetDefaultSelected = inSetDefaultSelected;
     226             :   // mIsSelected might have been changed by SetOptionsSelectedByIndex.  Possibly
     227             :   // more than once; make sure our mSelectedChanged state is set back correctly.
     228           0 :   mSelectedChanged = false;
     229             : 
     230           0 :   return NS_OK;
     231             : }
     232             : 
     233             : nsresult
     234           0 : HTMLOptionElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
     235             :                                 const nsAttrValue* aValue,
     236             :                                 const nsAttrValue* aOldValue, bool aNotify)
     237             : {
     238           0 :   if (aNameSpaceID == kNameSpaceID_None &&
     239           0 :       aName == nsGkAtoms::value && Selected()) {
     240             :     // Since this option is selected, changing value
     241             :     // may have changed missing validity state of the
     242             :     // Select element
     243           0 :     HTMLSelectElement* select = GetSelect();
     244           0 :     if (select) {
     245           0 :       select->UpdateValueMissingValidityState();
     246             :     }
     247             :   }
     248             : 
     249           0 :   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
     250           0 :                                             aValue, aOldValue, aNotify);
     251             : }
     252             : 
     253             : NS_IMETHODIMP
     254           0 : HTMLOptionElement::GetText(nsAString& aText)
     255             : {
     256           0 :   nsAutoString text;
     257             : 
     258           0 :   nsIContent* child = nsINode::GetFirstChild();
     259           0 :   while (child) {
     260           0 :     if (child->NodeType() == nsIDOMNode::TEXT_NODE ||
     261           0 :         child->NodeType() == nsIDOMNode::CDATA_SECTION_NODE) {
     262           0 :       child->AppendTextTo(text);
     263             :     }
     264           0 :     if (child->IsHTMLElement(nsGkAtoms::script) ||
     265           0 :         child->IsSVGElement(nsGkAtoms::script)) {
     266           0 :       child = child->GetNextNonChildNode(this);
     267             :     } else {
     268           0 :       child = child->GetNextNode(this);
     269             :     }
     270             :   }
     271             : 
     272             :   // XXX No CompressWhitespace for nsAString.  Sad.
     273           0 :   text.CompressWhitespace(true, true);
     274           0 :   aText = text;
     275             : 
     276           0 :   return NS_OK;
     277             : }
     278             : 
     279             : NS_IMETHODIMP
     280           0 : HTMLOptionElement::SetText(const nsAString& aText)
     281             : {
     282           0 :   return nsContentUtils::SetNodeTextContent(this, aText, true);
     283             : }
     284             : 
     285             : nsresult
     286           0 : HTMLOptionElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
     287             :                               nsIContent* aBindingParent,
     288             :                               bool aCompileEventHandlers)
     289             : {
     290           0 :   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
     291             :                                                  aBindingParent,
     292           0 :                                                  aCompileEventHandlers);
     293           0 :   NS_ENSURE_SUCCESS(rv, rv);
     294             : 
     295             :   // Our new parent might change :disabled/:enabled state.
     296           0 :   UpdateState(false);
     297             : 
     298           0 :   return NS_OK;
     299             : }
     300             : 
     301             : void
     302           0 : HTMLOptionElement::UnbindFromTree(bool aDeep, bool aNullParent)
     303             : {
     304           0 :   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
     305             : 
     306             :   // Our previous parent could have been involved in :disabled/:enabled state.
     307           0 :   UpdateState(false);
     308           0 : }
     309             : 
     310             : EventStates
     311           0 : HTMLOptionElement::IntrinsicState() const
     312             : {
     313           0 :   EventStates state = nsGenericHTMLElement::IntrinsicState();
     314           0 :   if (Selected()) {
     315           0 :     state |= NS_EVENT_STATE_CHECKED;
     316             :   }
     317           0 :   if (DefaultSelected()) {
     318           0 :     state |= NS_EVENT_STATE_DEFAULT;
     319             :   }
     320             : 
     321             :   // An <option> is disabled if it has @disabled set or if it's <optgroup> has
     322             :   // @disabled set.
     323           0 :   if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
     324           0 :     state |= NS_EVENT_STATE_DISABLED;
     325           0 :     state &= ~NS_EVENT_STATE_ENABLED;
     326             :   } else {
     327           0 :     nsIContent* parent = GetParent();
     328           0 :     if (parent && parent->IsHTMLElement(nsGkAtoms::optgroup) &&
     329           0 :         parent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
     330           0 :       state |= NS_EVENT_STATE_DISABLED;
     331           0 :       state &= ~NS_EVENT_STATE_ENABLED;
     332             :     } else {
     333           0 :       state &= ~NS_EVENT_STATE_DISABLED;
     334           0 :       state |= NS_EVENT_STATE_ENABLED;
     335             :     }
     336             :   }
     337             : 
     338           0 :   return state;
     339             : }
     340             : 
     341             : // Get the select content element that contains this option
     342             : HTMLSelectElement*
     343           0 : HTMLOptionElement::GetSelect()
     344             : {
     345           0 :   nsIContent* parent = GetParent();
     346           0 :   if (!parent) {
     347           0 :     return nullptr;
     348             :   }
     349             : 
     350           0 :   HTMLSelectElement* select = HTMLSelectElement::FromContent(parent);
     351           0 :   if (select) {
     352           0 :     return select;
     353             :   }
     354             : 
     355           0 :   if (!parent->IsHTMLElement(nsGkAtoms::optgroup)) {
     356           0 :     return nullptr;
     357             :   }
     358             : 
     359           0 :   return HTMLSelectElement::FromContentOrNull(parent->GetParent());
     360             : }
     361             : 
     362             : already_AddRefed<HTMLOptionElement>
     363           0 : HTMLOptionElement::Option(const GlobalObject& aGlobal,
     364             :                           const nsAString& aText,
     365             :                           const Optional<nsAString>& aValue,
     366             :                           bool aDefaultSelected,
     367             :                           bool aSelected,
     368             :                           ErrorResult& aError)
     369             : {
     370           0 :   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
     371             :   nsIDocument* doc;
     372           0 :   if (!win || !(doc = win->GetExtantDoc())) {
     373           0 :     aError.Throw(NS_ERROR_FAILURE);
     374           0 :     return nullptr;
     375             :   }
     376             : 
     377             :   already_AddRefed<mozilla::dom::NodeInfo> nodeInfo =
     378             :     doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::option, nullptr,
     379             :                                         kNameSpaceID_XHTML,
     380           0 :                                         nsIDOMNode::ELEMENT_NODE);
     381             : 
     382           0 :   RefPtr<HTMLOptionElement> option = new HTMLOptionElement(nodeInfo);
     383             : 
     384           0 :   if (!aText.IsEmpty()) {
     385             :     // Create a new text node and append it to the option
     386             :     RefPtr<nsTextNode> textContent =
     387           0 :       new nsTextNode(option->NodeInfo()->NodeInfoManager());
     388             : 
     389           0 :     textContent->SetText(aText, false);
     390             : 
     391           0 :     aError = option->AppendChildTo(textContent, false);
     392           0 :     if (aError.Failed()) {
     393           0 :       return nullptr;
     394             :     }
     395             :   }
     396             : 
     397           0 :   if (aValue.WasPassed()) {
     398             :     // Set the value attribute for this element. We're calling SetAttr
     399             :     // directly because we want to pass aNotify == false.
     400           0 :     aError = option->SetAttr(kNameSpaceID_None, nsGkAtoms::value,
     401           0 :                              aValue.Value(), false);
     402           0 :     if (aError.Failed()) {
     403           0 :       return nullptr;
     404             :     }
     405             :   }
     406             : 
     407           0 :   if (aDefaultSelected) {
     408             :     // We're calling SetAttr directly because we want to pass
     409             :     // aNotify == false.
     410           0 :     aError = option->SetAttr(kNameSpaceID_None, nsGkAtoms::selected,
     411           0 :                              EmptyString(), false);
     412           0 :     if (aError.Failed()) {
     413           0 :       return nullptr;
     414             :     }
     415             :   }
     416             : 
     417           0 :   option->SetSelected(aSelected, aError);
     418           0 :   if (aError.Failed()) {
     419           0 :     return nullptr;
     420             :   }
     421             : 
     422           0 :   option->SetSelectedChanged(false);
     423             : 
     424           0 :   return option.forget();
     425             : }
     426             : 
     427             : nsresult
     428           0 : HTMLOptionElement::CopyInnerTo(Element* aDest, bool aPreallocateChildren)
     429             : {
     430           0 :   nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
     431           0 :   NS_ENSURE_SUCCESS(rv, rv);
     432             : 
     433           0 :   if (aDest->OwnerDoc()->IsStaticDocument()) {
     434           0 :     static_cast<HTMLOptionElement*>(aDest)->SetSelected(Selected());
     435             :   }
     436           0 :   return NS_OK;
     437             : }
     438             : 
     439             : JSObject*
     440           0 : HTMLOptionElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     441             : {
     442           0 :   return HTMLOptionElementBinding::Wrap(aCx, this, aGivenProto);
     443             : }
     444             : 
     445             : } // namespace dom
     446             : } // namespace mozilla

Generated by: LCOV version 1.13