LCOV - code coverage report
Current view: directory - content/html/content/src - nsHTMLOptionElement.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 159 0 0.0 %
Date: 2012-06-02 Functions: 32 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      25                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsHTMLOptionElement.h"
      42                 : #include "nsHTMLSelectElement.h"
      43                 : #include "nsIDOMHTMLOptGroupElement.h"
      44                 : #include "nsIDOMHTMLFormElement.h"
      45                 : #include "nsIDOMEventTarget.h"
      46                 : #include "nsGkAtoms.h"
      47                 : #include "nsStyleConsts.h"
      48                 : #include "nsIFormControl.h"
      49                 : #include "nsIForm.h"
      50                 : #include "nsIDOMNode.h"
      51                 : #include "nsIDOMHTMLCollection.h"
      52                 : #include "nsISelectControlFrame.h"
      53                 : 
      54                 : // Notify/query select frame for selected state
      55                 : #include "nsIFormControlFrame.h"
      56                 : #include "nsIDocument.h"
      57                 : #include "nsIFrame.h"
      58                 : #include "nsIDOMHTMLSelectElement.h"
      59                 : #include "nsNodeInfoManager.h"
      60                 : #include "nsCOMPtr.h"
      61                 : #include "nsEventStates.h"
      62                 : #include "nsIDocument.h"
      63                 : #include "nsIDOMDocument.h"
      64                 : #include "nsContentCreatorFunctions.h"
      65                 : #include "mozAutoDocUpdate.h"
      66                 : 
      67                 : using namespace mozilla::dom;
      68                 : 
      69                 : /**
      70                 :  * Implementation of &lt;option&gt;
      71                 :  */
      72                 : 
      73                 : nsGenericHTMLElement*
      74               0 : NS_NewHTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo,
      75                 :                         FromParser aFromParser)
      76                 : {
      77                 :   /*
      78                 :    * nsHTMLOptionElement's will be created without a nsINodeInfo passed in
      79                 :    * if someone says "var opt = new Option();" in JavaScript, in a case like
      80                 :    * that we request the nsINodeInfo from the document's nodeinfo list.
      81                 :    */
      82               0 :   nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
      83               0 :   if (!nodeInfo) {
      84                 :     nsCOMPtr<nsIDocument> doc =
      85               0 :       do_QueryInterface(nsContentUtils::GetDocumentFromCaller());
      86               0 :     NS_ENSURE_TRUE(doc, nsnull);
      87                 : 
      88                 :     nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::option, nsnull,
      89                 :                                                    kNameSpaceID_XHTML,
      90               0 :                                                    nsIDOMNode::ELEMENT_NODE);
      91               0 :     NS_ENSURE_TRUE(nodeInfo, nsnull);
      92                 :   }
      93                 : 
      94               0 :   return new nsHTMLOptionElement(nodeInfo.forget());
      95                 : }
      96                 : 
      97               0 : nsHTMLOptionElement::nsHTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo)
      98                 :   : nsGenericHTMLElement(aNodeInfo),
      99                 :     mSelectedChanged(false),
     100                 :     mIsSelected(false),
     101               0 :     mIsInSetDefaultSelected(false)
     102                 : {
     103                 :   // We start off enabled
     104               0 :   AddStatesSilently(NS_EVENT_STATE_ENABLED);
     105               0 : }
     106                 : 
     107               0 : nsHTMLOptionElement::~nsHTMLOptionElement()
     108                 : {
     109               0 : }
     110                 : 
     111                 : // ISupports
     112                 : 
     113                 : 
     114               0 : NS_IMPL_ADDREF_INHERITED(nsHTMLOptionElement, nsGenericElement)
     115               0 : NS_IMPL_RELEASE_INHERITED(nsHTMLOptionElement, nsGenericElement)
     116                 : 
     117                 : 
     118               0 : DOMCI_NODE_DATA(HTMLOptionElement, nsHTMLOptionElement)
     119                 : 
     120                 : // QueryInterface implementation for nsHTMLOptionElement
     121               0 : NS_INTERFACE_TABLE_HEAD(nsHTMLOptionElement)
     122               0 :   NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLOptionElement,
     123                 :                                    nsIDOMHTMLOptionElement,
     124                 :                                    nsIJSNativeInitializer)
     125               0 :   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLOptionElement,
     126                 :                                                nsGenericHTMLElement)
     127               0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLOptionElement)
     128                 : 
     129                 : 
     130               0 : NS_IMPL_ELEMENT_CLONE(nsHTMLOptionElement)
     131                 : 
     132                 : 
     133                 : NS_IMETHODIMP
     134               0 : nsHTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
     135                 : {
     136               0 :   NS_ENSURE_ARG_POINTER(aForm);
     137               0 :   *aForm = nsnull;
     138                 : 
     139               0 :   nsHTMLSelectElement* selectControl = GetSelect();
     140                 : 
     141               0 :   if (selectControl) {
     142               0 :     selectControl->GetForm(aForm);
     143                 :   }
     144                 : 
     145               0 :   return NS_OK;
     146                 : }
     147                 : 
     148                 : void
     149               0 : nsHTMLOptionElement::SetSelectedInternal(bool aValue, bool aNotify)
     150                 : {
     151               0 :   mSelectedChanged = true;
     152               0 :   mIsSelected = aValue;
     153                 : 
     154                 :   // When mIsInSetDefaultSelected is true, the state change will be handled by
     155                 :   // SetAttr/UnsetAttr.
     156               0 :   if (!mIsInSetDefaultSelected) {
     157               0 :     UpdateState(aNotify);
     158                 :   }
     159               0 : }
     160                 : 
     161                 : NS_IMETHODIMP 
     162               0 : nsHTMLOptionElement::GetSelected(bool* aValue)
     163                 : {
     164               0 :   NS_ENSURE_ARG_POINTER(aValue);
     165               0 :   *aValue = Selected();
     166               0 :   return NS_OK;
     167                 : }
     168                 : 
     169                 : NS_IMETHODIMP
     170               0 : nsHTMLOptionElement::SetSelected(bool aValue)
     171                 : {
     172                 :   // Note: The select content obj maintains all the PresState
     173                 :   // so defer to it to get the answer
     174               0 :   nsHTMLSelectElement* selectInt = GetSelect();
     175               0 :   if (selectInt) {
     176                 :     PRInt32 index;
     177               0 :     GetIndex(&index);
     178                 :     // This should end up calling SetSelectedInternal
     179                 :     return selectInt->SetOptionsSelectedByIndex(index, index, aValue,
     180                 :                                                 false, true, true,
     181               0 :                                                 nsnull);
     182                 :   } else {
     183               0 :     SetSelectedInternal(aValue, true);
     184               0 :     return NS_OK;
     185                 :   }
     186                 : 
     187                 :   return NS_OK;
     188                 : }
     189                 : 
     190               0 : NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, selected)
     191                 : // GetText returns a whitespace compressed .textContent value.
     192               0 : NS_IMPL_STRING_ATTR_WITH_FALLBACK(nsHTMLOptionElement, Label, label, GetText)
     193               0 : NS_IMPL_STRING_ATTR_WITH_FALLBACK(nsHTMLOptionElement, Value, value, GetText)
     194               0 : NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, Disabled, disabled)
     195                 : 
     196                 : NS_IMETHODIMP
     197               0 : nsHTMLOptionElement::GetIndex(PRInt32* aIndex)
     198                 : {
     199                 :   // When the element is not in a list of options, the index is 0.
     200               0 :   *aIndex = 0;
     201                 : 
     202                 :   // Only select elements can contain a list of options.
     203               0 :   nsHTMLSelectElement* selectElement = GetSelect();
     204               0 :   if (!selectElement) {
     205               0 :     return NS_OK;
     206                 :   }
     207                 : 
     208               0 :   nsHTMLOptionCollection* options = selectElement->GetOptions();
     209               0 :   if (!options) {
     210               0 :     return NS_OK;
     211                 :   }
     212                 : 
     213                 :   // aIndex will not be set if GetOptionsIndex fails.
     214               0 :   return options->GetOptionIndex(this, 0, true, aIndex);
     215                 : }
     216                 : 
     217                 : bool
     218               0 : nsHTMLOptionElement::Selected() const
     219                 : {
     220                 :   // If we haven't been explictly selected or deselected, use our default value
     221               0 :   if (!mSelectedChanged) {
     222               0 :     return DefaultSelected();
     223                 :   }
     224                 : 
     225               0 :   return mIsSelected;
     226                 : }
     227                 : 
     228                 : bool
     229               0 : nsHTMLOptionElement::DefaultSelected() const
     230                 : {
     231               0 :   return HasAttr(kNameSpaceID_None, nsGkAtoms::selected);
     232                 : }
     233                 : 
     234                 : nsChangeHint
     235               0 : nsHTMLOptionElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
     236                 :                                             PRInt32 aModType) const
     237                 : {
     238                 :   nsChangeHint retval =
     239               0 :       nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
     240                 : 
     241               0 :   if (aAttribute == nsGkAtoms::label ||
     242                 :       aAttribute == nsGkAtoms::text) {
     243               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
     244                 :   }
     245               0 :   return retval;
     246                 : }
     247                 : 
     248                 : nsresult
     249               0 : nsHTMLOptionElement::BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
     250                 :                                    const nsAttrValueOrString* aValue,
     251                 :                                    bool aNotify)
     252                 : {
     253                 :   nsresult rv = nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName,
     254               0 :                                                     aValue, aNotify);
     255               0 :   NS_ENSURE_SUCCESS(rv, rv);
     256                 : 
     257               0 :   if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::selected ||
     258                 :       mSelectedChanged) {
     259               0 :     return NS_OK;
     260                 :   }
     261                 :   
     262                 :   // We just changed out selected state (since we look at the "selected"
     263                 :   // attribute when mSelectedChanged is false).  Let's tell our select about
     264                 :   // it.
     265               0 :   nsHTMLSelectElement* selectInt = GetSelect();
     266               0 :   if (!selectInt) {
     267               0 :     return NS_OK;
     268                 :   }
     269                 : 
     270                 :   // Note that at this point mSelectedChanged is false and as long as that's
     271                 :   // true it doesn't matter what value mIsSelected has.
     272               0 :   NS_ASSERTION(!mSelectedChanged, "Shouldn't be here");
     273                 :   
     274               0 :   bool newSelected = (aValue != nsnull);
     275               0 :   bool inSetDefaultSelected = mIsInSetDefaultSelected;
     276               0 :   mIsInSetDefaultSelected = true;
     277                 :   
     278                 :   PRInt32 index;
     279               0 :   GetIndex(&index);
     280                 :   // This should end up calling SetSelectedInternal, which we will allow to
     281                 :   // take effect so that parts of SetOptionsSelectedByIndex that might depend
     282                 :   // on it working don't get confused.
     283                 :   rv = selectInt->SetOptionsSelectedByIndex(index, index, newSelected,
     284                 :                                             false, true, aNotify,
     285               0 :                                             nsnull);
     286                 : 
     287                 :   // Now reset our members; when we finish the attr set we'll end up with the
     288                 :   // rigt selected state.
     289               0 :   mIsInSetDefaultSelected = inSetDefaultSelected;
     290               0 :   mSelectedChanged = false;
     291                 :   // mIsSelected doesn't matter while mSelectedChanged is false
     292                 : 
     293               0 :   return rv;
     294                 : }
     295                 : 
     296                 : NS_IMETHODIMP
     297               0 : nsHTMLOptionElement::GetText(nsAString& aText)
     298                 : {
     299               0 :   nsAutoString text;
     300               0 :   nsContentUtils::GetNodeTextContent(this, false, text);
     301                 : 
     302                 :   // XXX No CompressWhitespace for nsAString.  Sad.
     303               0 :   text.CompressWhitespace(true, true);
     304               0 :   aText = text;
     305                 : 
     306               0 :   return NS_OK;
     307                 : }
     308                 : 
     309                 : NS_IMETHODIMP
     310               0 : nsHTMLOptionElement::SetText(const nsAString& aText)
     311                 : {
     312               0 :   return nsContentUtils::SetNodeTextContent(this, aText, true);
     313                 : }
     314                 : 
     315                 : nsEventStates
     316               0 : nsHTMLOptionElement::IntrinsicState() const
     317                 : {
     318               0 :   nsEventStates state = nsGenericHTMLElement::IntrinsicState();
     319               0 :   if (Selected()) {
     320               0 :     state |= NS_EVENT_STATE_CHECKED;
     321                 :   }
     322               0 :   if (DefaultSelected()) {
     323               0 :     state |= NS_EVENT_STATE_DEFAULT;
     324                 :   }
     325                 : 
     326               0 :   if (HasAttr(kNameSpaceID_None, nsGkAtoms::disabled)) {
     327               0 :     state |= NS_EVENT_STATE_DISABLED;
     328               0 :     state &= ~NS_EVENT_STATE_ENABLED;
     329                 :   } else {
     330               0 :     state &= ~NS_EVENT_STATE_DISABLED;
     331               0 :     state |= NS_EVENT_STATE_ENABLED;
     332                 :   }
     333                 : 
     334                 :   return state;
     335                 : }
     336                 : 
     337                 : // Get the select content element that contains this option
     338                 : nsHTMLSelectElement*
     339               0 : nsHTMLOptionElement::GetSelect()
     340                 : {
     341               0 :   nsIContent* parent = this;
     342               0 :   while ((parent = parent->GetParent()) &&
     343               0 :          parent->IsHTML()) {
     344               0 :     if (parent->Tag() == nsGkAtoms::select) {
     345               0 :       return nsHTMLSelectElement::FromContent(parent);
     346                 :     }
     347               0 :     if (parent->Tag() != nsGkAtoms::optgroup) {
     348               0 :       break;
     349                 :     }
     350                 :   }
     351                 :   
     352               0 :   return nsnull;
     353                 : }
     354                 : 
     355                 : NS_IMETHODIMP    
     356               0 : nsHTMLOptionElement::Initialize(nsISupports* aOwner,
     357                 :                                 JSContext* aContext,
     358                 :                                 JSObject *aObj,
     359                 :                                 PRUint32 argc, 
     360                 :                                 jsval *argv)
     361                 : {
     362               0 :   nsresult result = NS_OK;
     363                 : 
     364               0 :   if (argc > 0) {
     365                 :     // The first (optional) parameter is the text of the option
     366               0 :     JSString* jsstr = JS_ValueToString(aContext, argv[0]);
     367               0 :     if (!jsstr) {
     368               0 :       return NS_ERROR_FAILURE;
     369                 :     }
     370                 : 
     371                 :     // Create a new text node and append it to the option
     372               0 :     nsCOMPtr<nsIContent> textContent;
     373               0 :     result = NS_NewTextNode(getter_AddRefs(textContent),
     374               0 :                             mNodeInfo->NodeInfoManager());
     375               0 :     if (NS_FAILED(result)) {
     376               0 :       return result;
     377                 :     }
     378                 : 
     379                 :     size_t length;
     380               0 :     const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
     381               0 :     if (!chars) {
     382               0 :       return NS_ERROR_FAILURE;
     383                 :     }
     384                 : 
     385               0 :     textContent->SetText(chars, length, false);
     386                 :     
     387               0 :     result = AppendChildTo(textContent, false);
     388               0 :     if (NS_FAILED(result)) {
     389               0 :       return result;
     390                 :     }
     391                 : 
     392               0 :     if (argc > 1) {
     393                 :       // The second (optional) parameter is the value of the option
     394               0 :       jsstr = JS_ValueToString(aContext, argv[1]);
     395               0 :       if (!jsstr) {
     396               0 :         return NS_ERROR_FAILURE;
     397                 :       }
     398                 : 
     399                 :       size_t length;
     400               0 :       const jschar *chars = JS_GetStringCharsAndLength(aContext, jsstr, &length);
     401               0 :       if (!chars) {
     402               0 :         return NS_ERROR_FAILURE;
     403                 :       }
     404                 : 
     405                 :       // Set the value attribute for this element
     406               0 :       nsAutoString value(chars, length);
     407                 : 
     408                 :       result = SetAttr(kNameSpaceID_None, nsGkAtoms::value, value,
     409               0 :                        false);
     410               0 :       if (NS_FAILED(result)) {
     411               0 :         return result;
     412                 :       }
     413                 : 
     414               0 :       if (argc > 2) {
     415                 :         // The third (optional) parameter is the defaultSelected value
     416                 :         JSBool defaultSelected;
     417               0 :         JS_ValueToBoolean(aContext, argv[2], &defaultSelected);
     418               0 :         if (defaultSelected) {
     419                 :           result = SetAttr(kNameSpaceID_None, nsGkAtoms::selected,
     420               0 :                            EmptyString(), false);
     421               0 :           NS_ENSURE_SUCCESS(result, result);
     422                 :         }
     423                 : 
     424                 :         // XXX This is *untested* behavior.  Should work though.
     425               0 :         if (argc > 3) {
     426                 :           JSBool selected;
     427               0 :           JS_ValueToBoolean(aContext, argv[3], &selected);
     428                 : 
     429               0 :           return SetSelected(selected);
     430                 :         }
     431                 :       }
     432                 :     }
     433                 :   }
     434                 : 
     435               0 :   return result;
     436                 : }
     437                 : 
     438                 : nsresult
     439               0 : nsHTMLOptionElement::CopyInnerTo(nsGenericElement* aDest) const
     440                 : {
     441               0 :   nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
     442               0 :   NS_ENSURE_SUCCESS(rv, rv);
     443                 : 
     444               0 :   if (aDest->OwnerDoc()->IsStaticDocument()) {
     445               0 :     static_cast<nsHTMLOptionElement*>(aDest)->SetSelected(Selected());
     446                 :   }
     447               0 :   return NS_OK;
     448                 : }
     449                 : 

Generated by: LCOV version 1.7