Get rid of dirt and sludge from the select interface, and add comments (bug 159242), r=rods@netscape.com, sr=jst@netscape.com

This commit is contained in:
jkeiser%netscape.com 2002-08-06 04:59:15 +00:00
parent e0bc31b94a
commit faf019ce38
6 changed files with 343 additions and 256 deletions

View File

@ -56,32 +56,30 @@ interface nsISelectElement : nsISupports
{
/**
* To be called when stuff is added under a child of
* the select--but *before* they are actually added.
* To be called when stuff is added under a child of the select--but *before*
* they are actually added.
*
* @param aOptions the content that was added (usually just an option, but
* could be an optgroup node with many child options)
* @param aParent the parent the options were added to (could be an optgroup)
* @param aContentIndex the index where the options are being added within the
* parent (if the parent is an optgroup, the index within the optgroup)
*/
[noscript] void willAddOptions(in nsIContent aOptions,
in nsIContent aParent,
in long aContentIndex);
/**
* To be called when stuff is removed under a child of
* the select--but *before* they are actually removed.
* To be called when stuff is removed under a child of the select--but
* *before* they are actually removed.
*
* @param aParent the parent the option(s) are being removed from
* @param aContentIndex the index of the option(s) within the parent (if the
* parent is an optgroup, the index within the optgroup)
*/
[noscript] void willRemoveOptions(in nsIContent aParent,
in long aContentIndex);
/**
* An OPTION element has been added to the SELECT's
* subtree.
*/
[noscript] void addOption(in nsIContent aContent);
/**
* An OPTION element has been deleted from the SELECT's
* subtree.
*/
[noscript] void removeOption(in nsIContent aContent);
/**
* Called when the parser is done adding child content
* to the select during document loading.
@ -96,24 +94,30 @@ interface nsISelectElement : nsISupports
*/
boolean isDoneAddingChildren();
/**
* Returns whether we're the option is selected
*/
boolean isOptionSelected(in nsIDOMHTMLOptionElement aOption);
/**
* Sets an option selected or delselected
*/
void setOptionSelected(in nsIDOMHTMLOptionElement aOption,
in boolean aIsSelected);
/**
* Checks whether an option is disabled (even if it's part of an optgroup)
*
* @param aIndex the index of the option to check
* @return whether the option is disabled
*/
boolean isOptionDisabled(in long aIndex);
/**
* Sets multiple options (or just sets startIndex if select is single)
* and handles notifications and cleanup and everything under the sun.
* When this method exits, the select will be in a consistent state. i.e.
* if you set the last option to false, it will select an option anyway.
*
* @param aStartIndex the first index to set
* @param aEndIndex the last index to set (set same as first index for one
* option)
* @param aIsSelected whether to set the option(s) to true or false
* @param aClearAll whether to clear all other options (for example, if you
* are normal-clicking on the current option)
* @param aSetDisabled whether it is permissible to set disabled options
* (for JavaScript)
* @param aNotify whether to notify frames and such
* @return whether any options were actually changed
*/
boolean setOptionsSelectedByIndex(in long aStartIndex,
in long aEndIndex,
@ -122,22 +126,17 @@ interface nsISelectElement : nsISupports
in boolean aSetDisabled,
in boolean aNotify);
/**
* Called when an option is disabled
*/
void onOptionDisabled(in nsIDOMHTMLOptionElement aOption);
/**
* Called to save/restore to/from pres. state
*/
[noscript] void saveState();
[noscript] void restoreState(in nsIPresState aState);
/**
* Finds the index of a given option element
*
* @param aOption the option to get the index of
* @param aStartIndex the index to start looking at
* @param aForward TRUE to look forward, FALSE to look backward
* @return the option index
*/
long getOptionIndex(in nsIDOMHTMLOptionElement aOption,
in long aStartIndex, in boolean aForward);
/** Whether or not there are optgroups in this select */
readonly attribute boolean hasOptGroups;
};

View File

@ -50,6 +50,9 @@
#include "nsIDOMHTMLSelectElement.h"
/**
* The implementation of <optgroup>
*/
class nsHTMLOptGroupElement : public nsGenericHTMLContainerElement,
public nsIDOMHTMLOptGroupElement
{
@ -90,7 +93,11 @@ public:
protected:
nsresult GetSelect(nsISelectElement **aSelectElement);
/**
* Get the select content element that contains this option
* @param aSelectElement the select element [OUT]
*/
void GetSelect(nsISelectElement **aSelectElement);
};
nsresult
@ -222,8 +229,7 @@ nsHTMLOptGroupElement::SizeOf(nsISizeOfHandler* aSizer,
#endif
// Get the select content element that contains this option
nsresult
void
nsHTMLOptGroupElement::GetSelect(nsISelectElement **aSelectElement)
{
*aSelectElement = nsnull;
@ -239,8 +245,6 @@ nsHTMLOptGroupElement::GetSelect(nsISelectElement **aSelectElement)
prevParent = parent;
prevParent->GetParent(*getter_AddRefs(parent));
}
return NS_OK;
}
// nsIContent

View File

@ -70,6 +70,9 @@
#include "nsIEventStateManager.h"
#include "nsXULAtoms.h"
/**
* Implementation of <option>
*/
class nsHTMLOptionElement : public nsGenericHTMLContainerElement,
public nsIDOMHTMLOptionElement,
public nsIJSNativeInitializer,
@ -327,8 +330,12 @@ nsHTMLOptionElement::SetSelected(PRBool aValue)
GetSelect(getter_AddRefs(selectElement));
nsCOMPtr<nsISelectElement> selectInt(do_QueryInterface(selectElement));
if (selectInt) {
PRInt32 index;
GetIndex(&index);
// This should end up calling SetSelectedInternal
return selectInt->SetOptionSelected(this, aValue);
return selectInt->SetOptionsSelectedByIndex(index, index, PR_TRUE,
PR_FALSE, PR_TRUE, PR_TRUE,
nsnull);
} else {
return SetSelectedInternal(aValue, PR_TRUE);
}

View File

@ -85,7 +85,10 @@
class nsHTMLSelectElement;
// nsHTMLOptionCollection
/**
* The collection of options in the select (what you get back when you do
* select.options in DOM)
*/
class nsHTMLOptionCollection: public nsIDOMNSHTMLOptionCollection,
public nsGenericDOMHTMLCollection
{
@ -106,20 +109,47 @@ public:
// nsIDOMHTMLCollection interface
NS_DECL_NSIDOMHTMLCOLLECTION
nsresult InsertElementAt(nsIDOMNode* aOption, PRInt32 aIndex);
// Helpers for nsHTMLSelectElement
/**
* Insert an option
* @param aOption the option to insert
* @param aIndex the index to insert at
*/
nsresult InsertElementAt(nsIDOMHTMLOptionElement* aOption, PRInt32 aIndex);
/**
* Remove an option
* @param aIndex the index of the option to remove
*/
nsresult RemoveElementAt(PRInt32 aIndex);
nsresult GetOption(PRInt32 aIndex, nsIDOMHTMLOptionElement** aReturn);
/**
* Get the index of an option
* @param aOption the option
* @return the index
*/
PRInt32 IndexOf(nsIContent* aOption);
/**
* Get the option at the index
* @param aIndex the index
* @param aReturn the option returned [OUT]
*/
nsresult ItemAsOption(PRInt32 aIndex, nsIDOMHTMLOptionElement **aReturn);
/**
* Drop the reference to the select. Called during select destruction.
*/
void DropReference();
private:
/** The list of options (holds strong references) */
nsCOMPtr<nsISupportsArray> mElements;
/** The select element that contains this array */
nsHTMLSelectElement* mSelect;
};
/**
* Implementation of &lt;select&gt;
*/
class nsHTMLSelectElement : public nsGenericHTMLContainerFormElement,
public nsIDOMHTMLSelectElement,
public nsIDOMNSHTMLSelectElement,
@ -177,6 +207,8 @@ public:
NS_IMETHOD Reset();
NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
nsIContent* aSubmitElement);
NS_IMETHOD SaveState();
NS_IMETHOD RestoreState(nsIPresState* aState);
// nsISelectElement
NS_DECL_NSISELECTELEMENT
@ -191,18 +223,46 @@ public:
protected:
// Helper Methods
nsresult IsOptionSelectedByIndex(PRInt32 index, PRBool* aIsSelected);
nsresult FindSelectedIndex(PRInt32 aStartIndex);
nsresult SelectSomething();
nsresult CheckSelectSomething();
nsresult OnOptionSelected(nsISelectControlFrame* aSelectFrame,
nsIPresContext* aPresContext,
PRInt32 aIndex,
PRBool aSelected,
PRBool aNotify);
nsresult InitializeOption(nsIDOMHTMLOptionElement* aOption,
PRUint32* aNumOptions);
nsresult RestoreStateTo(nsAString* aNewSelected);
/**
* Check whether the option specified by the index is selected
* @param aIndex the index
* @return whether the option at the index is selected
*/
PRBool IsOptionSelectedByIndex(PRInt32 aIndex);
/**
* Starting with (and including) aStartIndex, find the first selected index
* and set mSelectedIndex to it.
* @param aStartIndex the index to start with
*/
void FindSelectedIndex(PRInt32 aStartIndex);
/**
* Select some option if possible (generally the first non-disabled option).
*/
void SelectSomething();
/**
* Call SelectSomething(), but only if nothing is selected
* @see SelectSomething()
*/
void CheckSelectSomething();
/**
* Called to trigger notifications of frames and fixing selected index
*
* @param aSelectFrame the frame for this content (could be null)
* @param aPresContext the current pres context
* @param aIndex the index that was selected or deselected
* @param aSelected whether the index was selected or deselected
* @param aNotify whether to notify the style system and such
*/
void OnOptionSelected(nsISelectControlFrame* aSelectFrame,
nsIPresContext* aPresContext,
PRInt32 aIndex,
PRBool aSelected,
PRBool aNotify);
/**
* Restore state to a particular state string (representing the options)
* @param aNewSelected the state string to restore to
*/
void RestoreStateTo(nsAString* aNewSelected);
#ifdef DEBUG_john
// Don't remove these, por favor. They're very useful in debugging
@ -210,38 +270,113 @@ protected:
#endif
// Adding options
/**
* Insert option(s) into the options[] array and perform notifications
* @param aOptions the option or optgroup being added
* @param aListIndex the index to start adding options into the list at
* @param aDepth the depth of aOptions (1=direct child of select ...)
*/
nsresult InsertOptionsIntoList(nsIContent* aOptions,
PRInt32 aListIndex,
PRInt32 aLevel);
PRInt32 aDepth);
/**
* Remove option(s) from the options[] array
* @param aOptions the option or optgroup being added
* @param aListIndex the index to start removing options from the list at
* @param aDepth the depth of aOptions (1=direct child of select ...)
*/
nsresult RemoveOptionsFromList(nsIContent* aOptions,
PRInt32 aListIndex,
PRInt32 aLevel);
PRInt32 aDepth);
/**
* Insert option(s) into the options[] array (called by InsertOptionsIntoList)
* @param aOptions the option or optgroup being added
* @param aInsertIndex the index to start adding options into the list at
* @param aDepth the depth of aOptions (1=direct child of select ...)
*/
nsresult InsertOptionsIntoListRecurse(nsIContent* aOptions,
PRInt32* aInsertIndex,
PRInt32 aLevel);
PRInt32 aDepth);
/**
* Remove option(s) from the options[] array (called by RemoveOptionsFromList)
* @param aOptions the option or optgroup being added
* @param aListIndex the index to start removing options from the list at
* @param aNumRemoved the number removed so far [OUT]
* @param aDepth the depth of aOptions (1=direct child of select ...)
*/
nsresult RemoveOptionsFromListRecurse(nsIContent* aOptions,
PRInt32 aRemoveIndex,
PRInt32* aNumRemoved,
PRInt32 aLevel);
nsresult GetContentLevel(nsIContent* aContent, PRInt32* aLevel);
nsresult GetOptionAt(nsIContent* aOptions, PRInt32* aListIndex);
nsresult GetOptionAfter(nsIContent* aOptions, PRInt32* aListIndex);
nsresult GetFirstOptionIndex(nsIContent* aOptions, PRInt32* aListIndex);
nsresult GetFirstChildOptionIndex(nsIContent* aOptions,
PRInt32 aStartIndex,
PRInt32 aEndIndex,
PRInt32* aListIndex);
PRInt32 aDepth);
/**
* Find out how deep this content is from the select (1=direct child)
* @param aContent the content to check
* @return the depth
*/
PRInt32 GetContentDepth(nsIContent* aContent);
/**
* Get the index of the first option at, under or following the content in
* the select, or length of options[] if none are found
* @param aOptions the content
* @return the index of the first option
*/
PRInt32 GetOptionIndexAt(nsIContent* aOptions);
/**
* Get the next option following the content in question (not at or under)
* (this could include siblings of the current content or siblings of the
* parent or children of siblings of the parent).
* @param aOptions the content
* @return the index of the next option after the content
*/
PRInt32 GetOptionIndexAfter(nsIContent* aOptions);
/**
* Get the first option index at or under the content in question.
* @param aOptions the content
* @return the index of the first option at or under the content
*/
PRInt32 GetFirstOptionIndex(nsIContent* aOptions);
/**
* Get the first option index under the content in question, within the
* range specified.
* @param aOptions the content
* @param aStartIndex the first child to look at
* @param aEndIndex the child *after* the last child to look at
* @return the index of the first option at or under the content
*/
PRInt32 GetFirstChildOptionIndex(nsIContent* aOptions,
PRInt32 aStartIndex,
PRInt32 aEndIndex);
/**
* Get the frame as an nsISelectControlFrame (MAY RETURN NULL)
* @return the select frame, or null
*/
nsISelectControlFrame *GetSelectFrame();
// Helper method for dispatching custom DOM events to our anonymous subcontent
/**
* Helper method for dispatching custom DOM events to our anonymous subcontent
* (for XBL form controls)
* @param aName the name of the event to dispatch
*/
void DispatchDOMEvent(const nsAString& aName);
/** The options[] array */
nsHTMLOptionCollection* mOptions;
/** false if the parser is in the middle of adding children. */
PRBool mIsDoneAddingChildren;
/** The number of non-options as children of the select */
PRUint32 mArtifactsAtTopLevel;
/** The number of optgroups anywhere under the select */
PRUint32 mOptGroupCount;
/**
* The current selected index for selectedIndex (will be the first selected
* index if multiple are selected)
*/
PRInt32 mSelectedIndex;
/**
* The temporary restore state in case we try to restore before parser is
* done adding options
*/
nsString* mRestoreState;
};
@ -419,10 +554,11 @@ nsHTMLSelectElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
nsresult
nsHTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
PRInt32 aListIndex,
PRInt32 aLevel)
PRInt32 aDepth)
{
PRInt32 insertIndex = aListIndex;
InsertOptionsIntoListRecurse(aOptions, &insertIndex, aLevel);
nsresult rv = InsertOptionsIntoListRecurse(aOptions, &insertIndex, aDepth);
NS_ENSURE_SUCCESS(rv, rv);
// Deal with the selected list
if (insertIndex - aListIndex) {
@ -516,10 +652,13 @@ nsHTMLSelectElement::PrintOptions(nsIContent* aOptions, PRInt32 tabs)
nsresult
nsHTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
PRInt32 aListIndex,
PRInt32 aLevel)
PRInt32 aDepth)
{
PRInt32 numRemoved = 0;
RemoveOptionsFromListRecurse(aOptions, aListIndex, &numRemoved, aLevel);
nsresult rv = RemoveOptionsFromListRecurse(aOptions, aListIndex, &numRemoved,
aDepth);
NS_ENSURE_SUCCESS(rv, rv);
if (numRemoved) {
// Tell the widget we removed the options
nsISelectControlFrame* selectFrame = GetSelectFrame();
@ -558,7 +697,7 @@ nsHTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
nsresult
nsHTMLSelectElement::InsertOptionsIntoListRecurse(nsIContent* aOptions,
PRInt32* aInsertIndex,
PRInt32 aLevel)
PRInt32 aDepth)
{
// We *assume* here that someone's brain has not gone horribly
// wrong by putting <option> inside of <option>. I'm sorry, I'm
@ -567,15 +706,15 @@ nsHTMLSelectElement::InsertOptionsIntoListRecurse(nsIContent* aOptions,
nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
if (optElement) {
nsCOMPtr<nsIDOMNode> optNode(do_QueryInterface(optElement));
mOptions->InsertElementAt(optNode, *aInsertIndex);
nsresult rv = mOptions->InsertElementAt(optElement, *aInsertIndex);
NS_ENSURE_SUCCESS(rv, rv);
(*aInsertIndex)++;
return NS_OK;
}
// If it's at the top level, then we just found out there are non-options
// at the top level, which will throw off the insert count
if (aLevel == 0) {
if (aDepth == 0) {
mArtifactsAtTopLevel++;
}
@ -598,7 +737,8 @@ nsHTMLSelectElement::InsertOptionsIntoListRecurse(nsIContent* aOptions,
nsCOMPtr<nsIContent> child;
for (PRInt32 i=0;i<numChildren;i++) {
aOptions->ChildAt(i,*getter_AddRefs(child));
InsertOptionsIntoListRecurse(child, aInsertIndex, aLevel+1);
nsresult rv = InsertOptionsIntoListRecurse(child, aInsertIndex, aDepth+1);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -610,7 +750,7 @@ nsresult
nsHTMLSelectElement::RemoveOptionsFromListRecurse(nsIContent* aOptions,
PRInt32 aRemoveIndex,
PRInt32* aNumRemoved,
PRInt32 aLevel) {
PRInt32 aDepth) {
// We *assume* here that someone's brain has not gone horribly
// wrong by putting <option> inside of <option>. I'm sorry, I'm
// just not going to look for an option inside of an option.
@ -618,13 +758,14 @@ nsHTMLSelectElement::RemoveOptionsFromListRecurse(nsIContent* aOptions,
nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
if (optElement) {
mOptions->RemoveElementAt(aRemoveIndex);
nsresult rv = mOptions->RemoveElementAt(aRemoveIndex);
NS_ENSURE_SUCCESS(rv, rv);
(*aNumRemoved)++;
return NS_OK;
}
// Yay, one less artifact at the top level.
if (aLevel == 0) {
if (aDepth == 0) {
mArtifactsAtTopLevel--;
}
@ -649,7 +790,8 @@ nsHTMLSelectElement::RemoveOptionsFromListRecurse(nsIContent* aOptions,
nsCOMPtr<nsIContent> child;
for (PRInt32 i=0;i<numChildren;i++) {
aOptions->ChildAt(i,*getter_AddRefs(child));
RemoveOptionsFromListRecurse(child, aRemoveIndex, aNumRemoved, aLevel+1);
nsresult rv = RemoveOptionsFromListRecurse(child, aRemoveIndex, aNumRemoved, aDepth+1);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
@ -660,8 +802,7 @@ nsHTMLSelectElement::WillAddOptions(nsIContent* aOptions,
nsIContent* aParent,
PRInt32 aContentIndex)
{
PRInt32 level;
GetContentLevel(aParent, &level);
PRInt32 level = GetContentDepth(aParent);
if (level == -1) {
return NS_ERROR_FAILURE;
}
@ -671,27 +812,31 @@ nsHTMLSelectElement::WillAddOptions(nsIContent* aOptions,
PRInt32 children;
aParent->ChildCount(children);
if (aContentIndex >= children) {
GetOptionAfter(aParent, &ind);
// If the content insert is after the end of the parent, then we want to get
// the next index *after* the parent and insert there.
ind = GetOptionIndexAfter(aParent);
} else {
// If the content insert is somewhere in the middle of the container, then
// we want to get the option currently at the index and insert in front of
// that.
nsCOMPtr<nsIContent> currentKid;
aParent->ChildAt(aContentIndex, *getter_AddRefs(currentKid));
NS_ASSERTION(currentKid, "Child not found!");
if (currentKid) {
GetOptionAt(currentKid, &ind);
ind = GetOptionIndexAt(currentKid);
}
}
InsertOptionsIntoList(aOptions, ind, level);
return NS_OK;
return InsertOptionsIntoList(aOptions, ind, level);
}
NS_IMETHODIMP
nsHTMLSelectElement::WillRemoveOptions(nsIContent* aParent,
PRInt32 aContentIndex)
{
PRInt32 level;
GetContentLevel(aParent, &level);
nsresult rv = NS_OK;
PRInt32 level = GetContentDepth(aParent);
if (level == -1) {
return NS_ERROR_FAILURE;
}
@ -700,51 +845,50 @@ nsHTMLSelectElement::WillRemoveOptions(nsIContent* aParent,
nsCOMPtr<nsIContent> currentKid;
aParent->ChildAt(aContentIndex, *getter_AddRefs(currentKid));
if (currentKid) {
PRInt32 ind = -1;
GetFirstOptionIndex(currentKid, &ind);
PRInt32 ind = GetFirstOptionIndex(currentKid);
if (ind != -1) {
RemoveOptionsFromList(currentKid, ind, level);
rv = RemoveOptionsFromList(currentKid, ind, level);
}
}
return NS_OK;
return rv;
}
nsresult
nsHTMLSelectElement::GetContentLevel(nsIContent* aContent, PRInt32* aLevel)
PRInt32
nsHTMLSelectElement::GetContentDepth(nsIContent* aContent)
{
nsCOMPtr<nsIContent> content = aContent;
nsCOMPtr<nsIContent> prevContent;
*aLevel = 0;
PRInt32 retval = 0;
while (content != this) {
(*aLevel)++;
retval++;
prevContent = content;
prevContent->GetParent(*getter_AddRefs(content));
if (!content) {
*aLevel = -1;
retval = -1;
break;
}
}
return NS_OK;
return retval;
}
nsresult
nsHTMLSelectElement::GetOptionAt(nsIContent* aOptions, PRInt32* aListIndex)
PRInt32
nsHTMLSelectElement::GetOptionIndexAt(nsIContent* aOptions)
{
// Search this node and below.
// If not found, find the first one *after* this node.
GetFirstOptionIndex(aOptions, aListIndex);
if (*aListIndex == -1) {
GetOptionAfter(aOptions, aListIndex);
PRInt32 retval = GetFirstOptionIndex(aOptions);
if (retval == -1) {
retval = GetOptionIndexAfter(aOptions);
}
return NS_OK;
return retval;
}
nsresult
nsHTMLSelectElement::GetOptionAfter(nsIContent* aOptions, PRInt32* aListIndex)
PRInt32
nsHTMLSelectElement::GetOptionIndexAfter(nsIContent* aOptions)
{
// - If this is the select, the next option is the last.
// - If not, search all the options after aOptions and up to the last option
@ -753,63 +897,65 @@ nsHTMLSelectElement::GetOptionAfter(nsIContent* aOptions, PRInt32* aListIndex)
if (aOptions == this) {
PRUint32 len;
GetLength(&len);
*aListIndex = len;
} else {
nsCOMPtr<nsIContent> parent;
aOptions->GetParent(*getter_AddRefs(parent));
return len;
}
if (parent) {
PRInt32 index;
PRInt32 count;
parent->IndexOf(aOptions, index);
parent->ChildCount(count);
PRInt32 retval = -1;
GetFirstChildOptionIndex(parent, index+1, count, aListIndex);
nsCOMPtr<nsIContent> parent;
aOptions->GetParent(*getter_AddRefs(parent));
if ((*aListIndex) == -1) {
GetOptionAfter(parent, aListIndex);
}
if (parent) {
PRInt32 index;
PRInt32 count;
parent->IndexOf(aOptions, index);
parent->ChildCount(count);
retval = GetFirstChildOptionIndex(parent, index+1, count);
if (retval == -1) {
retval = GetOptionIndexAfter(parent);
}
}
return NS_OK;
return retval;
}
nsresult
nsHTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions,
PRInt32* aListIndex)
PRInt32
nsHTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
{
PRInt32 listIndex = -1;
nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
if (optElement) {
GetOptionIndex(optElement, 0, PR_TRUE, aListIndex);
GetOptionIndex(optElement, 0, PR_TRUE, &listIndex);
// If you nested stuff under the option, you're just plain
// screwed. *I'm* not going to aid and abet your evil deed.
return NS_OK;
return listIndex;
}
PRInt32 numChildren;
aOptions->ChildCount(numChildren);
GetFirstChildOptionIndex(aOptions, 0, numChildren, aListIndex);
listIndex = GetFirstChildOptionIndex(aOptions, 0, numChildren);
return NS_OK;
return listIndex;
}
nsresult
PRInt32
nsHTMLSelectElement::GetFirstChildOptionIndex(nsIContent* aOptions,
PRInt32 aStartIndex,
PRInt32 aEndIndex,
PRInt32* aListIndex)
PRInt32 aEndIndex)
{
PRInt32 retval = -1;
nsCOMPtr<nsIContent> child;
for (PRInt32 i=aStartIndex;i<aEndIndex;i++) {
aOptions->ChildAt(i,*getter_AddRefs(child));
GetFirstOptionIndex(child, aListIndex);
if ((*aListIndex) != -1) {
return NS_OK;
retval = GetFirstOptionIndex(child);
if (retval != -1) {
break;
}
}
return NS_OK;
return retval;
}
nsISelectControlFrame *
@ -1011,42 +1157,19 @@ nsHTMLSelectElement::GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsHTMLSelectElement::IsOptionSelected(nsIDOMHTMLOptionElement* aOption,
PRBool * aIsSelected)
{
// start off by assuming it isn't in the list of index objects
*aIsSelected = PR_FALSE;
// first find the index of the incoming option
PRInt32 index = -1;
if (NS_FAILED(GetOptionIndex(aOption, 0, PR_TRUE, &index))) {
return NS_ERROR_FAILURE;
}
return IsOptionSelectedByIndex(index, aIsSelected);
}
nsresult
nsHTMLSelectElement::IsOptionSelectedByIndex(PRInt32 index,
PRBool * aIsSelected)
PRBool
nsHTMLSelectElement::IsOptionSelectedByIndex(PRInt32 aIndex)
{
nsCOMPtr<nsIDOMHTMLOptionElement> option;
mOptions->ItemAsOption(index, getter_AddRefs(option));
mOptions->ItemAsOption(aIndex, getter_AddRefs(option));
PRBool isSelected = PR_FALSE;
if (option) {
return option->GetSelected(aIsSelected);
} else {
return NS_OK;
option->GetSelected(&isSelected);
}
return isSelected;
}
NS_IMETHODIMP
nsHTMLSelectElement::OnOptionDisabled(nsIDOMHTMLOptionElement* anOption)
{
return NS_OK;
}
nsresult
void
nsHTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
nsIPresContext* aPresContext,
PRInt32 aIndex,
@ -1073,41 +1196,20 @@ nsHTMLSelectElement::OnOptionSelected(nsISelectControlFrame* aSelectFrame,
if (aSelectFrame) {
aSelectFrame->OnOptionSelected(aPresContext, aIndex, aSelected);
}
return NS_OK;
}
nsresult
void
nsHTMLSelectElement::FindSelectedIndex(PRInt32 aStartIndex)
{
mSelectedIndex = -1;
PRUint32 len;
GetLength(&len);
for (PRInt32 i=aStartIndex; i<(PRInt32)len; i++) {
PRBool isSelected;
IsOptionSelectedByIndex(i, &isSelected);
if (isSelected) {
if (IsOptionSelectedByIndex(i)) {
mSelectedIndex = i;
break;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLSelectElement::SetOptionSelected(nsIDOMHTMLOptionElement* anOption,
PRBool aIsSelected)
{
PRInt32 index;
nsresult rv = GetOptionIndex(anOption, 0, PR_TRUE, &index);
if (NS_FAILED(rv)) {
return rv;
}
return SetOptionsSelectedByIndex(index, index, aIsSelected,
PR_FALSE, PR_TRUE, PR_TRUE, nsnull);
}
// XXX Consider splitting this into two functions for ease of reading:
@ -1594,7 +1696,7 @@ nsHTMLSelectElement::NamedItem(const nsAString& aName,
return mOptions->NamedItem(aName, aReturn);
}
nsresult
void
nsHTMLSelectElement::CheckSelectSomething()
{
if (mIsDoneAddingChildren) {
@ -1606,23 +1708,21 @@ nsHTMLSelectElement::CheckSelectSomething()
SelectSomething();
}
}
return NS_OK;
}
nsresult
void
nsHTMLSelectElement::SelectSomething()
{
// If we're not done building the select, don't play with this yet.
if (!mIsDoneAddingChildren) {
return NS_OK;
return;
}
// Don't select anything if we're disabled
PRBool isDisabled = PR_FALSE;
GetDisabled(&isDisabled);
if (isDisabled) {
return NS_OK;
return;
}
PRUint32 count;
@ -1636,25 +1736,6 @@ nsHTMLSelectElement::SelectSomething()
break;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLSelectElement::AddOption(nsIContent* aContent)
{
nsCOMPtr<nsIDOMHTMLElement> domElement(do_QueryInterface(aContent));
return Add(domElement, nsnull);
}
NS_IMETHODIMP
nsHTMLSelectElement::RemoveOption(nsIContent* aContent)
{
// XXX We're *trusting* that this content is actually a child
// of the select. Bad things may happen if not.
nsCOMPtr<nsIDOMNode> ret;
nsCOMPtr<nsIDOMNode> toRemove(do_QueryInterface(aContent));
return RemoveChild(toRemove, getter_AddRefs(ret));
}
NS_IMETHODIMP
@ -1892,16 +1973,16 @@ nsHTMLSelectElement::GetBoxObject(nsIBoxObject** aResult)
return nsDoc->GetBoxObjectFor(NS_STATIC_CAST(nsIDOMElement*, this), aResult);
}
nsresult
void
nsHTMLSelectElement::RestoreStateTo(nsAString* aNewSelected)
{
if (!mIsDoneAddingChildren) {
mRestoreState = new nsString;
if (!mRestoreState) {
return NS_OK;
return;
}
*mRestoreState = *aNewSelected;
return NS_OK;
return;
}
PRUint32 len;
@ -1925,21 +2006,18 @@ nsHTMLSelectElement::RestoreStateTo(nsAString* aNewSelected)
}
//CheckSelectSomething();
return NS_OK;
}
nsresult
NS_IMETHODIMP
nsHTMLSelectElement::Reset()
{
PRBool isMultiple;
nsresult rv = GetMultiple(&isMultiple);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 count = 0;
PRUint32 numSelected = 0;
//
// Cycle through the options array and reset the options
//
PRUint32 numOptions;
rv = GetLength(&numOptions);
nsresult rv = GetLength(&numOptions);
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < numOptions; i++) {
@ -1951,19 +2029,38 @@ nsHTMLSelectElement::Reset()
NS_ASSERTION(option, "option not an OptionElement");
if (option) {
InitializeOption(option, &count);
//
// Reset the option to its default value
//
PRBool selected = PR_FALSE;
option->GetDefaultSelected(&selected);
SetOptionsSelectedByIndex(i, i, selected,
PR_FALSE, PR_TRUE, PR_TRUE, nsnull);
if (selected) {
numSelected++;
}
}
}
//
// If nothing was selected and it's not multiple, select something
//
PRInt32 size = 1;
GetSize(&size);
if (count == 0 && !isMultiple && size <= 1) {
PRBool isMultiple = PR_FALSE;
GetMultiple(&isMultiple);
if (numSelected == 0 && !isMultiple && size <= 1) {
SelectSomething();
}
//
// Let the frame know we were reset
//
// Don't flush, if there's no frame yet it won't care about us being
// reset even if we forced it to be created now.
//
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
if (formControlFrame) {
formControlFrame->OnContentReset();
@ -1972,23 +2069,6 @@ nsHTMLSelectElement::Reset()
return NS_OK;
}
nsresult
nsHTMLSelectElement::InitializeOption(nsIDOMHTMLOptionElement * aOption,
PRUint32* aNumOptions)
{
PRBool selected;
nsresult rv = aOption->GetDefaultSelected(&selected);
if (NS_FAILED(rv)) {
selected = PR_FALSE;
}
SetOptionSelected(aOption, selected);
if (selected) {
(*aNumOptions)++;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLSelectElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
nsIContent* aSubmitElement)
@ -2265,7 +2345,8 @@ nsHTMLOptionCollection::NamedItem(const nsAString& aName,
}
nsresult
nsHTMLOptionCollection::InsertElementAt(nsIDOMNode* aOption, PRInt32 aIndex)
nsHTMLOptionCollection::InsertElementAt(nsIDOMHTMLOptionElement* aOption,
PRInt32 aIndex)
{
return mElements->InsertElementAt(aOption, aIndex);
}

View File

@ -661,9 +661,7 @@ void nsListControlFrame::PaintFocus(nsIRenderingContext& aRC, nsFramePaintLayer
nsCOMPtr<nsIDOMNode> node;
if (NS_SUCCEEDED(selectNSElement->Item(focusedIndex, getter_AddRefs(node)))) {
nsCOMPtr<nsIDOMHTMLOptionElement> domOpt(do_QueryInterface(node));
if (domOpt) {
selectElement->IsOptionSelected(domOpt, &lastItemIsSelected);
}
domOpt->GetSelected(&lastItemIsSelected);
}
// set up back stop colors and then ask L&F service for the real colors

View File

@ -661,9 +661,7 @@ void nsListControlFrame::PaintFocus(nsIRenderingContext& aRC, nsFramePaintLayer
nsCOMPtr<nsIDOMNode> node;
if (NS_SUCCEEDED(selectNSElement->Item(focusedIndex, getter_AddRefs(node)))) {
nsCOMPtr<nsIDOMHTMLOptionElement> domOpt(do_QueryInterface(node));
if (domOpt) {
selectElement->IsOptionSelected(domOpt, &lastItemIsSelected);
}
domOpt->GetSelected(&lastItemIsSelected);
}
// set up back stop colors and then ask L&F service for the real colors