gecko/content/html/content/src/nsHTMLFieldSetElement.cpp

238 lines
6.9 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2012-05-21 04:12:37 -07:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsHTMLFieldSetElement.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMEventTarget.h"
#include "nsStyleConsts.h"
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsGUIEvent.h"
#include "nsEventDispatcher.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(FieldSet)
nsHTMLFieldSetElement::nsHTMLFieldSetElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLFormElement(aNodeInfo)
, mElements(nsnull)
, mFirstLegend(nsnull)
{
// <fieldset> is always barred from constraint validation.
SetBarredFromConstraintValidation(true);
// We start out enabled
AddStatesSilently(NS_EVENT_STATE_ENABLED);
}
nsHTMLFieldSetElement::~nsHTMLFieldSetElement()
{
PRUint32 length = mDependentElements.Length();
for (PRUint32 i = 0; i < length; ++i) {
mDependentElements[i]->ForgetFieldSet(this);
}
}
// nsISupports
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLFieldSetElement,
nsGenericHTMLFormElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mElements)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLFieldSetElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLFieldSetElement,
nsGenericHTMLFormElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mElements, nsIDOMNodeList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(nsHTMLFieldSetElement, nsGenericElement)
NS_IMPL_RELEASE_INHERITED(nsHTMLFieldSetElement, nsGenericElement)
DOMCI_NODE_DATA(HTMLFieldSetElement, nsHTMLFieldSetElement)
// QueryInterface implementation for nsHTMLFieldSetElement
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLFieldSetElement)
NS_HTML_CONTENT_INTERFACE_TABLE2(nsHTMLFieldSetElement,
nsIDOMHTMLFieldSetElement,
nsIConstraintValidation)
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLFieldSetElement,
nsGenericHTMLFormElement)
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLFieldSetElement)
NS_IMPL_ELEMENT_CLONE(nsHTMLFieldSetElement)
NS_IMPL_BOOL_ATTR(nsHTMLFieldSetElement, Disabled, disabled)
NS_IMPL_STRING_ATTR(nsHTMLFieldSetElement, Name, name)
// nsIConstraintValidation
NS_IMPL_NSICONSTRAINTVALIDATION(nsHTMLFieldSetElement)
// nsIContent
nsresult
nsHTMLFieldSetElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
// Do not process any DOM events if the element is disabled.
aVisitor.mCanHandle = false;
if (IsElementDisabledForEvents(aVisitor.mEvent->message, NULL)) {
return NS_OK;
}
return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
}
nsresult
nsHTMLFieldSetElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::disabled &&
nsINode::GetFirstChild()) {
if (!mElements) {
mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
true);
}
PRUint32 length = mElements->Length(true);
for (PRUint32 i=0; i<length; ++i) {
static_cast<nsGenericHTMLFormElement*>(mElements->GetNodeAt(i))
->FieldSetDisabledChanged(aNotify);
}
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
// nsIDOMHTMLFieldSetElement
NS_IMETHODIMP
nsHTMLFieldSetElement::GetForm(nsIDOMHTMLFormElement** aForm)
{
return nsGenericHTMLFormElement::GetForm(aForm);
}
NS_IMETHODIMP
nsHTMLFieldSetElement::GetType(nsAString& aType)
{
aType.AssignLiteral("fieldset");
return NS_OK;
}
/* static */
bool
nsHTMLFieldSetElement::MatchListedElements(nsIContent* aContent, PRInt32 aNamespaceID,
nsIAtom* aAtom, void* aData)
{
nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(aContent);
return formControl && formControl->GetType() != NS_FORM_LABEL &&
formControl->GetType() != NS_FORM_METER;
}
NS_IMETHODIMP
nsHTMLFieldSetElement::GetElements(nsIDOMHTMLCollection** aElements)
{
if (!mElements) {
mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
true);
}
NS_ADDREF(*aElements = mElements);
return NS_OK;
}
// nsIFormControl
nsresult
nsHTMLFieldSetElement::Reset()
{
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFieldSetElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
{
return NS_OK;
}
nsresult
nsHTMLFieldSetElement::InsertChildAt(nsIContent* aChild, PRUint32 aIndex,
bool aNotify)
{
bool firstLegendHasChanged = false;
if (aChild->IsHTML(nsGkAtoms::legend)) {
if (!mFirstLegend) {
mFirstLegend = aChild;
// We do not want to notify the first time mFirstElement is set.
} else {
// If mFirstLegend is before aIndex, we do not change it.
// Otherwise, mFirstLegend is now aChild.
if (PRInt32(aIndex) <= IndexOf(mFirstLegend)) {
mFirstLegend = aChild;
firstLegendHasChanged = true;
}
}
}
nsresult rv = nsGenericHTMLFormElement::InsertChildAt(aChild, aIndex, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (firstLegendHasChanged) {
NotifyElementsForFirstLegendChange(aNotify);
}
return rv;
}
void
nsHTMLFieldSetElement::RemoveChildAt(PRUint32 aIndex, bool aNotify)
{
bool firstLegendHasChanged = false;
if (mFirstLegend && (GetChildAt(aIndex) == mFirstLegend)) {
// If we are removing the first legend we have to found another one.
nsIContent* child = mFirstLegend->GetNextSibling();
mFirstLegend = nsnull;
firstLegendHasChanged = true;
for (; child; child = child->GetNextSibling()) {
if (child->IsHTML(nsGkAtoms::legend)) {
mFirstLegend = child;
break;
}
}
}
nsGenericHTMLFormElement::RemoveChildAt(aIndex, aNotify);
if (firstLegendHasChanged) {
NotifyElementsForFirstLegendChange(aNotify);
}
}
void
nsHTMLFieldSetElement::NotifyElementsForFirstLegendChange(bool aNotify)
{
/**
* NOTE: this could be optimized if only call when the fieldset is currently
* disabled.
* This should also make sure that mElements is set when we happen to be here.
* However, this method shouldn't be called very often in normal use cases.
*/
if (!mElements) {
mElements = new nsContentList(this, MatchListedElements, nsnull, nsnull,
true);
}
PRUint32 length = mElements->Length(true);
for (PRUint32 i = 0; i < length; ++i) {
static_cast<nsGenericHTMLFormElement*>(mElements->GetNodeAt(i))
->FieldSetFirstLegendChanged(aNotify);
}
}