DOM: getting rid of JS_GetContextPrivate wherever possible. Use static parent links where we can. When we do need to find this info about the caller we call a function that knows how to get that info rather than inline calls to JS_GetContextPrivate. This is all required for calling DOM objects on non-DOM JSContexts as we do via xpconnect. XPConnect: basic refactoring work to disassociate wrappers from the JSContext that was active when the wrapper was constructed. This allows for calling into wrapped JS objects on the right JSContext and for proper grouping of wrapped native objects so that they can share proto objects. This also allows for better sharing of objects and lays the foundations for threadsafety and interface flattening. Also, xpconnect tests are reorganized and improved. fixes bugs: 13419, 17736, 17746, 17952, 22086 r=vidur r=mccabe r=norris r=cbegle a=chofmann git-svn-id: svn://10.0.0.236/trunk@56202 18797224-902f-48f8-a5cc-f745e15eee43
646 lines
20 KiB
C++
646 lines
20 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
#include "nsIDOMHTMLOptionElement.h"
|
|
#include "nsIDOMHTMLOptGroupElement.h"
|
|
#include "nsIDOMHTMLFormElement.h"
|
|
#include "nsIScriptObjectOwner.h"
|
|
#include "nsIDOMEventReceiver.h"
|
|
#include "nsIHTMLContent.h"
|
|
#include "nsGenericHTMLElement.h"
|
|
#include "nsHTMLAtoms.h"
|
|
#include "nsHTMLIIDs.h"
|
|
#include "nsIStyleContext.h"
|
|
#include "nsIMutableStyleContext.h"
|
|
#include "nsStyleConsts.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIFormControl.h"
|
|
#include "nsIForm.h"
|
|
#include "nsIDOMText.h"
|
|
#include "nsITextContent.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsGenericElement.h"
|
|
#include "nsIDOMHTMLCollection.h"
|
|
#include "nsIJSNativeInitializer.h"
|
|
#include "nsISelectElement.h"
|
|
#include "nsISelectControlFrame.h"
|
|
#include "nsIComboboxControlFrame.h"
|
|
|
|
// Notify/query select frame for selected state
|
|
#include "nsIFormControlFrame.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsIDOMHTMLSelectElement.h"
|
|
|
|
|
|
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLOptGroupElementIID, NS_IDOMHTMLOPTIONELEMENT_IID);
|
|
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
|
|
static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
|
|
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
|
|
static NS_DEFINE_IID(kISelectElementIID, NS_ISELECTELEMENT_IID);
|
|
static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID);
|
|
static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID);
|
|
static NS_DEFINE_IID(kIJSNativeInitializerIID, NS_IJSNATIVEINITIALIZER_IID);
|
|
|
|
class nsHTMLOptionElement : public nsIDOMHTMLOptionElement,
|
|
public nsIScriptObjectOwner,
|
|
public nsIDOMEventReceiver,
|
|
public nsIHTMLContent,
|
|
public nsIJSNativeInitializer
|
|
//public nsIFormControl
|
|
{
|
|
public:
|
|
nsHTMLOptionElement(nsIAtom* aTag);
|
|
virtual ~nsHTMLOptionElement();
|
|
|
|
// nsISupports
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIDOMNode
|
|
NS_IMPL_IDOMNODE_USING_GENERIC(mInner)
|
|
|
|
// nsIDOMElement
|
|
NS_IMPL_IDOMELEMENT_USING_GENERIC(mInner)
|
|
|
|
// nsIDOMHTMLElement
|
|
NS_IMPL_IDOMHTMLELEMENT_USING_GENERIC(mInner)
|
|
|
|
// nsIDOMHTMLOptionElement
|
|
NS_IMETHOD GetForm(nsIDOMHTMLFormElement** aForm);
|
|
NS_IMETHOD GetDefaultSelected(PRBool* aDefaultSelected);
|
|
NS_IMETHOD SetDefaultSelected(PRBool aDefaultSelected);
|
|
NS_IMETHOD GetText(nsString& aText);
|
|
NS_IMETHOD GetIndex(PRInt32* aIndex);
|
|
NS_IMETHOD SetIndex(PRInt32 aIndex);
|
|
NS_IMETHOD GetDisabled(PRBool* aDisabled);
|
|
NS_IMETHOD SetDisabled(PRBool aDisabled);
|
|
NS_IMETHOD GetLabel(nsString& aLabel);
|
|
NS_IMETHOD SetLabel(const nsString& aLabel);
|
|
NS_IMETHOD GetSelected(PRBool* aSelected);
|
|
NS_IMETHOD SetSelected(PRBool aValue);
|
|
NS_IMETHOD GetValue(nsString& aValue);
|
|
NS_IMETHOD SetValue(const nsString& aValue);
|
|
|
|
// nsIScriptObjectOwner
|
|
NS_IMPL_ISCRIPTOBJECTOWNER_USING_GENERIC(mInner)
|
|
|
|
// nsIDOMEventReceiver
|
|
NS_IMPL_IDOMEVENTRECEIVER_USING_GENERIC(mInner)
|
|
|
|
// nsIContent
|
|
NS_IMPL_ICONTENT_NO_SETPARENT_USING_GENERIC(mInner)
|
|
|
|
// nsIHTMLContent
|
|
NS_IMPL_IHTMLCONTENT_USING_GENERIC(mInner)
|
|
|
|
// nsIJSNativeInitializer
|
|
NS_IMETHOD Initialize(JSContext* aContext, JSObject *aObj,
|
|
PRUint32 argc, jsval *argv);
|
|
|
|
protected:
|
|
nsGenericHTMLContainerElement mInner;
|
|
|
|
// Get the primary frame associated with this content
|
|
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame);
|
|
|
|
// Get the select content element that contains this option
|
|
nsresult GetSelect(nsIDOMHTMLSelectElement *&aSelectElement);
|
|
};
|
|
|
|
nsresult
|
|
NS_NewHTMLOptionElement(nsIHTMLContent** aInstancePtrResult, nsIAtom* aTag)
|
|
{
|
|
NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
|
|
if (nsnull == aInstancePtrResult) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
nsIHTMLContent* it = new nsHTMLOptionElement(aTag);
|
|
if (nsnull == it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return it->QueryInterface(kIHTMLContentIID, (void**) aInstancePtrResult);
|
|
}
|
|
|
|
|
|
nsHTMLOptionElement::nsHTMLOptionElement(nsIAtom* aTag)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mInner.Init(this, aTag);
|
|
}
|
|
|
|
nsHTMLOptionElement::~nsHTMLOptionElement()
|
|
{
|
|
}
|
|
|
|
// ISupports
|
|
|
|
NS_IMPL_ADDREF(nsHTMLOptionElement)
|
|
NS_IMPL_RELEASE(nsHTMLOptionElement)
|
|
|
|
nsresult
|
|
nsHTMLOptionElement::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
NS_IMPL_HTML_CONTENT_QUERY_INTERFACE(aIID, aInstancePtr, this)
|
|
if (aIID.Equals(kIDOMHTMLOptionElementIID)) {
|
|
*aInstancePtr = (void*)(nsIDOMHTMLOptionElement*) this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kIJSNativeInitializerIID)) {
|
|
nsIJSNativeInitializer* tmp = this;
|
|
*aInstancePtr = (void*) tmp;
|
|
AddRef();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
// the option has a ref to the form, but not vice versa. The form can get to the
|
|
// options via the select.
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::SetParent(nsIContent* aParent)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
// Remove us from our old select element
|
|
if (nsnull != mInner.mParent) {
|
|
nsIDOMHTMLSelectElement* oldSelectElement = nsnull;
|
|
GetSelect(oldSelectElement);
|
|
if (nsnull != oldSelectElement) {
|
|
nsISelectElement* sel;
|
|
|
|
if (NS_SUCCEEDED(oldSelectElement->QueryInterface(kISelectElementIID, (void**)&sel))) {
|
|
sel->RemoveOption(this);
|
|
NS_RELEASE(sel);
|
|
}
|
|
|
|
NS_RELEASE(oldSelectElement);
|
|
}
|
|
}
|
|
|
|
result = mInner.SetParent(aParent);
|
|
|
|
if (nsnull != aParent) {
|
|
nsIDOMHTMLSelectElement* newSelectElement = nsnull;
|
|
GetSelect(newSelectElement);
|
|
if (nsnull != newSelectElement) {
|
|
nsISelectElement* sel;
|
|
|
|
if (NS_SUCCEEDED(newSelectElement->QueryInterface(kISelectElementIID, (void**)&sel))) {
|
|
sel->AddOption(this);
|
|
NS_RELEASE(sel);
|
|
}
|
|
|
|
NS_RELEASE(newSelectElement);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsHTMLOptionElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
|
|
{
|
|
nsHTMLOptionElement* it = new nsHTMLOptionElement(mInner.mTag);
|
|
if (nsnull == it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
mInner.CopyInnerTo(this, &it->mInner, aDeep);
|
|
return it->QueryInterface(kIDOMNodeIID, (void**) aReturn);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
|
{
|
|
nsIDOMHTMLSelectElement* selectElement = nsnull;
|
|
nsresult res = GetSelect(selectElement);
|
|
if (NS_OK == res) {
|
|
nsIFormControl* selectControl = nsnull;
|
|
res = selectElement->QueryInterface(kIFormControlIID, (void**)&selectControl);
|
|
NS_RELEASE(selectElement);
|
|
|
|
if (NS_OK == res) {
|
|
res = selectControl->GetForm(aForm);
|
|
NS_RELEASE(selectControl);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetSelected(PRBool* aValue)
|
|
{
|
|
nsIFormControlFrame* formControlFrame = nsnull;
|
|
nsresult rv = GetPrimaryFrame(formControlFrame);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
PRInt32 indx;
|
|
if (NS_OK == GetIndex(&indx)) {
|
|
nsString value;
|
|
value.Append(indx, 10); // Save the index in base 10
|
|
formControlFrame->GetProperty(nsHTMLAtoms::selected, value);
|
|
if (value == "1")
|
|
*aValue = PR_TRUE;
|
|
else
|
|
*aValue = PR_FALSE;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::SetSelected(PRBool aValue)
|
|
{
|
|
nsIFormControlFrame* fcFrame = nsnull;
|
|
nsresult result = GetPrimaryFrame(fcFrame);
|
|
if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) {
|
|
nsISelectControlFrame* selectFrame = nsnull;
|
|
result = fcFrame->QueryInterface(nsISelectControlFrame::GetIID(),(void **) &selectFrame);
|
|
if (NS_SUCCEEDED(result) && (nsnull != selectFrame)) {
|
|
PRInt32 indx;
|
|
result = GetIndex(&indx);
|
|
if (NS_SUCCEEDED(result)) {
|
|
selectFrame->SetOptionSelected(indx, aValue);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, defaultselected)
|
|
//NS_IMPL_INT_ATTR(nsHTMLOptionElement, Index, index)
|
|
NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, Disabled, disabled)
|
|
//NS_IMPL_STRING_ATTR(nsHTMLOptionElement, Label, label)
|
|
NS_IMPL_STRING_ATTR(nsHTMLOptionElement, Value, value)
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetLabel(nsString& aValue)
|
|
{
|
|
mInner.GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::label, aValue);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::SetLabel(const nsString& aValue)
|
|
{
|
|
nsresult result = mInner.SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::label, aValue, PR_TRUE);
|
|
if (NS_SUCCEEDED(result)) {
|
|
nsIFormControlFrame* fcFrame = nsnull;
|
|
nsresult result = GetPrimaryFrame(fcFrame);
|
|
if (NS_SUCCEEDED(result) && (nsnull != fcFrame)) {
|
|
nsIComboboxControlFrame* selectFrame = nsnull;
|
|
result = fcFrame->QueryInterface(nsIComboboxControlFrame::GetIID(),(void **) &selectFrame);
|
|
if (NS_SUCCEEDED(result) && (nsnull != selectFrame)) {
|
|
selectFrame->UpdateSelection(PR_FALSE, PR_TRUE, 0);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetDefaultSelected(PRBool* aDefaultSelected)
|
|
{
|
|
nsHTMLValue val;
|
|
nsresult rv = mInner.GetHTMLAttribute(nsHTMLAtoms::selected, val);
|
|
*aDefaultSelected = (NS_CONTENT_ATTR_NOT_THERE != rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::SetDefaultSelected(PRBool aDefaultSelected)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsHTMLValue empty(eHTMLUnit_Empty);
|
|
if (aDefaultSelected) {
|
|
rv = mInner.SetHTMLAttribute(nsHTMLAtoms::selected, empty, PR_TRUE);
|
|
} else {
|
|
rv = mInner.UnsetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::selected, PR_TRUE);
|
|
}
|
|
if (NS_SUCCEEDED(rv)) {
|
|
// When setting DefaultSelected, we must also reset Selected (DOM Errata)
|
|
rv = SetSelected(aDefaultSelected);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetIndex(PRInt32* aIndex)
|
|
{
|
|
nsresult res = NS_ERROR_FAILURE;
|
|
*aIndex = -1; // -1 indicates the index was not found
|
|
|
|
// Get our nsIDOMNode interface to compare apples to apples.
|
|
nsIDOMNode* thisNode = nsnull;
|
|
if (NS_OK == this->QueryInterface(kIDOMNodeIID, (void**)&thisNode)) {
|
|
|
|
// Get our containing select content object.
|
|
nsIDOMHTMLSelectElement* selectElement = nsnull;
|
|
if (NS_OK == GetSelect(selectElement)) {
|
|
|
|
// Get the options from the select object.
|
|
nsIDOMHTMLCollection* options = nsnull;
|
|
if (NS_OK == selectElement->GetOptions(&options)) {
|
|
|
|
// Walk the options to find out where we are in the list (ick, O(n))
|
|
PRUint32 length = 0;
|
|
options->GetLength(&length);
|
|
nsIDOMNode* thisOption = nsnull;
|
|
for (PRUint32 i = 0; i < length; i++) {
|
|
options->Item(i, &thisOption);
|
|
if (thisNode == thisOption) {
|
|
res = NS_OK;
|
|
*aIndex = i;
|
|
break;
|
|
}
|
|
NS_IF_RELEASE(thisOption);
|
|
}
|
|
NS_RELEASE(options);
|
|
}
|
|
NS_RELEASE(selectElement);
|
|
}
|
|
NS_RELEASE(thisNode);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// This method does nothing for now as Index is supposed to be a read-only property
|
|
// (See the DOM Errata)
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::SetIndex(PRInt32 aIndex)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::StringToAttribute(nsIAtom* aAttribute,
|
|
const nsString& aValue,
|
|
nsHTMLValue& aResult)
|
|
{
|
|
if (aAttribute == nsHTMLAtoms::selected) {
|
|
aResult.SetEmptyValue();
|
|
return NS_CONTENT_ATTR_HAS_VALUE;
|
|
}
|
|
else if (aAttribute == nsHTMLAtoms::disabled) {
|
|
aResult.SetEmptyValue();
|
|
return NS_CONTENT_ATTR_HAS_VALUE;
|
|
}
|
|
return NS_CONTENT_ATTR_NOT_THERE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::AttributeToString(nsIAtom* aAttribute,
|
|
const nsHTMLValue& aValue,
|
|
nsString& aResult) const
|
|
{
|
|
return mInner.AttributeToString(aAttribute, aValue, aResult);
|
|
}
|
|
|
|
static void
|
|
MapAttributesInto(const nsIHTMLMappedAttributes* aAttributes,
|
|
nsIMutableStyleContext* aContext,
|
|
nsIPresContext* aPresContext)
|
|
{
|
|
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aContext, aPresContext);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetMappedAttributeImpact(const nsIAtom* aAttribute,
|
|
PRInt32& aHint) const
|
|
{
|
|
if (aAttribute == nsHTMLAtoms::label) {
|
|
aHint = NS_STYLE_HINT_REFLOW;
|
|
} else if (! nsGenericHTMLElement::GetCommonMappedAttributesImpact(aAttribute, aHint)) {
|
|
aHint = NS_STYLE_HINT_CONTENT;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetAttributeMappingFunctions(nsMapAttributesFunc& aFontMapFunc,
|
|
nsMapAttributesFunc& aMapFunc) const
|
|
{
|
|
aFontMapFunc = nsnull;
|
|
aMapFunc = &MapAttributesInto;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::HandleDOMEvent(nsIPresContext* aPresContext,
|
|
nsEvent* aEvent,
|
|
nsIDOMEvent** aDOMEvent,
|
|
PRUint32 aFlags,
|
|
nsEventStatus* aEventStatus)
|
|
{
|
|
return mInner.HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
|
|
aFlags, aEventStatus);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::GetText(nsString& aText)
|
|
{
|
|
aText.SetLength(0);
|
|
PRInt32 numNodes;
|
|
nsresult rv = mInner.ChildCount(numNodes);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
for (PRInt32 i = 0; i < numNodes; i++) {
|
|
nsIContent* node;
|
|
rv = ChildAt(i, node);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
nsIDOMText* domText = nsnull;
|
|
rv = node->QueryInterface(kIDOMTextIID, (void**)&domText);
|
|
if (NS_SUCCEEDED(rv) && domText) {
|
|
rv = domText->GetData(aText);
|
|
// the option could be all spaces, so compress the white space
|
|
// then make sure the length is greater than zero
|
|
if (aText.Length() > 0) {
|
|
nsAutoString compressText = aText;
|
|
compressText.CompressWhitespace(PR_TRUE, PR_TRUE);
|
|
if (compressText.Length() != 0) {
|
|
aText = compressText;
|
|
}
|
|
}
|
|
NS_RELEASE(domText);
|
|
NS_RELEASE(node);
|
|
break;
|
|
}
|
|
NS_RELEASE(node);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
// Options don't have frames - get the select content node
|
|
// then call nsGenericHTMLElement::GetPrimaryFrame()
|
|
nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame)
|
|
{
|
|
nsIDOMHTMLSelectElement* selectElement = nsnull;
|
|
nsresult res = GetSelect(selectElement);
|
|
if (NS_OK == res) {
|
|
nsIHTMLContent* selectContent = nsnull;
|
|
nsresult gotContent = selectElement->QueryInterface(kIContentIID, (void**)&selectContent);
|
|
NS_RELEASE(selectElement);
|
|
|
|
if (NS_OK == gotContent) {
|
|
res = nsGenericHTMLElement::GetPrimaryFrame(selectContent, aIFormControlFrame);
|
|
NS_RELEASE(selectContent);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// Get the select content element that contains this option
|
|
nsresult nsHTMLOptionElement::GetSelect(nsIDOMHTMLSelectElement *&aSelectElement)
|
|
{
|
|
// Get the containing element (Either a select or an optGroup)
|
|
nsIDOMNode* parentNode = nsnull;
|
|
nsresult res = NS_ERROR_FAILURE;
|
|
if (NS_OK == this->GetParentNode(&parentNode)) {
|
|
aSelectElement = nsnull;
|
|
if (nsnull != parentNode) {
|
|
|
|
res = parentNode->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&aSelectElement);
|
|
|
|
// If we are in an OptGroup we need to GetParentNode again (at least once)
|
|
if (NS_OK != res) {
|
|
nsIDOMHTMLOptGroupElement* optgroupElement = nsnull;
|
|
while (1) { // Be ready for nested OptGroups
|
|
if ((nsnull != parentNode) && (NS_OK == parentNode->QueryInterface(kIDOMHTMLOptGroupElementIID, (void**)&optgroupElement))) {
|
|
NS_RELEASE(optgroupElement); // Don't need the optgroup, just seeing if it IS one.
|
|
nsIDOMNode* grandParentNode = nsnull;
|
|
if (NS_OK == parentNode->GetParentNode(&grandParentNode)) {
|
|
NS_RELEASE(parentNode);
|
|
parentNode = grandParentNode;
|
|
} else {
|
|
break; // Break out if we can't get our parent (we're screwed)
|
|
}
|
|
} else {
|
|
break; // Break out if not a OptGroup (hopefully we have a select)
|
|
}
|
|
}
|
|
res = parentNode->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&aSelectElement);
|
|
}
|
|
|
|
// We have a select if we're gonna get one, so let go of the generic node
|
|
NS_RELEASE(parentNode);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::Initialize(JSContext* aContext,
|
|
JSObject *aObj,
|
|
PRUint32 argc,
|
|
jsval *argv)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
if (argc > 0) {
|
|
// The first (optional) parameter is the text of the option
|
|
JSString* jsstr = JS_ValueToString(aContext, argv[0]);
|
|
if (nsnull != jsstr) {
|
|
// Create a new text node and append it to the option
|
|
nsIContent* textNode;
|
|
nsITextContent* content;
|
|
|
|
result = NS_NewTextNode(&textNode);
|
|
if (NS_FAILED(result)) {
|
|
return result;
|
|
}
|
|
|
|
result = textNode->QueryInterface(kITextContentIID, (void**)&content);
|
|
if (NS_FAILED(result)) {
|
|
return result;
|
|
}
|
|
|
|
result = content->SetText(JS_GetStringChars(jsstr),
|
|
JS_GetStringLength(jsstr),
|
|
PR_FALSE);
|
|
NS_RELEASE(content);
|
|
if (NS_FAILED(result)) {
|
|
return result;
|
|
}
|
|
|
|
result = mInner.AppendChildTo(textNode, PR_FALSE);
|
|
if (NS_FAILED(result)) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (argc > 1) {
|
|
// The second (optional) parameter is the value of the option
|
|
jsstr = JS_ValueToString(aContext, argv[1]);
|
|
if (nsnull != jsstr) {
|
|
// Set the value attribute for this element
|
|
nsAutoString value(JS_GetStringChars(jsstr));
|
|
|
|
result = mInner.SetAttribute(kNameSpaceID_HTML,
|
|
nsHTMLAtoms::value,
|
|
value,
|
|
PR_FALSE);
|
|
if (NS_FAILED(result)) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (argc > 2) {
|
|
// The third (optional) parameter is the defaultSelected value
|
|
JSBool defaultSelected;
|
|
if ((JS_TRUE == JS_ValueToBoolean(aContext,
|
|
argv[2],
|
|
&defaultSelected)) &&
|
|
(JS_TRUE == defaultSelected)) {
|
|
nsHTMLValue empty(eHTMLUnit_Empty);
|
|
result = mInner.SetHTMLAttribute(nsHTMLAtoms::selected,
|
|
empty,
|
|
PR_FALSE);
|
|
if (NS_FAILED(result)) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// XXX Since we don't store the selected state, we can't deal
|
|
// with the fourth (optional) parameter that is meant to specify
|
|
// whether the option element should be currently selected or
|
|
// not. Does anyone depend on this behavior?
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsHTMLOptionElement::SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const
|
|
{
|
|
return mInner.SizeOf(aSizer, aResult, sizeof(*this));
|
|
}
|