Bug 17003. Give textareas a childnode and connect that childnode to .defaultValue. Also make textareas work properly for display: none;

r=jkeiser sr=jst
This commit is contained in:
sicking%bigfoot.com 2001-12-23 16:06:13 +00:00
parent be60da33e3
commit 4c02c1d0fa
4 changed files with 191 additions and 77 deletions

View File

@ -69,6 +69,9 @@
#include "nsGUIEvent.h"
#include "nsLinebreakConverter.h"
#include "nsIPresState.h"
#include "nsIDOMText.h"
#include "nsReadableUtils.h"
#include "nsITextContent.h"
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
@ -117,6 +120,13 @@ public:
NS_IMETHOD SetValueChanged(PRBool aValueChanged);
// nsIContent
NS_IMETHOD InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify,
PRBool aDeepSetDocument);
NS_IMETHOD ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify,
PRBool aDeepSetDocument);
NS_IMETHOD AppendChildTo(nsIContent* aKid, PRBool aNotify,
PRBool aDeepSetDocument);
NS_IMETHOD RemoveChildAt(PRInt32 aIndex, PRBool aNotify);
NS_IMETHOD StringToAttribute(nsIAtom* aAttribute,
const nsAReadableString& aValue,
nsHTMLValue& aResult);
@ -134,6 +144,8 @@ public:
protected:
nsCOMPtr<nsIControllers> mControllers;
char* mValue;
PRPackedBool mValueChanged;
NS_IMETHOD SelectAll(nsIPresContext* aPresContext);
};
@ -167,6 +179,8 @@ NS_NewHTMLTextAreaElement(nsIHTMLContent** aInstancePtrResult,
nsHTMLTextAreaElement::nsHTMLTextAreaElement()
{
mValue = 0;
mValueChanged = PR_FALSE;
}
nsHTMLTextAreaElement::~nsHTMLTextAreaElement()
@ -410,10 +424,13 @@ nsHTMLTextAreaElement::GetValue(nsAWritableString& aValue)
formControlFrame->GetProperty(nsHTMLAtoms::value, aValue);
return NS_OK;
} else {
return nsGenericHTMLContainerFormElement::GetAttr(kNameSpaceID_HTML,
nsHTMLAtoms::value,
aValue);
if (!mValueChanged || !mValue) {
GetDefaultValue(aValue);
} else {
aValue = NS_ConvertUTF8toUCS2(mValue);
}
}
return NS_OK;
}
@ -443,14 +460,15 @@ nsHTMLTextAreaElement::SetValueGuaranteed(const nsAString& aValue,
formControlFrame->SetProperty(presContext, nsHTMLAtoms::value, aValue);
}
else {
if (mValue) {
nsMemory::Free(mValue);
}
mValue = ToNewUTF8String(aValue);
NS_ENSURE_TRUE(mValue, NS_ERROR_OUT_OF_MEMORY);
// Always set the value internally, since it affects layout
//
// Set the attribute in the DOM too, we call SetAttribute with aNotify
// false so that we don't generate unnecessary reflows.
nsGenericHTMLContainerFormElement::SetAttr(kNameSpaceID_HTML,
nsHTMLAtoms::value, aValue,
PR_FALSE);
SetValueChanged(PR_TRUE);
}
return NS_OK;
}
@ -465,41 +483,136 @@ nsHTMLTextAreaElement::SetValue(const nsAReadableString& aValue)
NS_IMETHODIMP
nsHTMLTextAreaElement::SetValueChanged(PRBool aValueChanged)
{
mValueChanged = aValueChanged;
if (!aValueChanged && mValue) {
nsMemory::Free(mValue);
mValue = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::GetDefaultValue(nsAWritableString& aDefaultValue)
{
nsGenericHTMLContainerFormElement::GetAttr(kNameSpaceID_HTML,
nsHTMLAtoms::defaultvalue,
aDefaultValue);
nsresult rv;
PRInt32 nChildren, i;
return NS_OK;
nsAutoString defVal;
ChildCount(nChildren);
for (i = 0; i < nChildren; i++) {
nsCOMPtr<nsIContent> child;
nsCOMPtr<nsIDOMText> textNode;
rv = ChildAt(i, *getter_AddRefs(child));
NS_ENSURE_SUCCESS(rv, rv);
textNode = do_QueryInterface(child);
if(textNode) {
nsAutoString tmp;
textNode->GetData(tmp);
defVal.Append(tmp);
}
}
aDefaultValue.Assign(defVal);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::SetDefaultValue(const nsAReadableString& aDefaultValue)
{
nsAutoString defaultValue(aDefaultValue);
nsresult rv;
PRInt32 nChildren, i;
PRBool firstChildUsed = PR_FALSE;
// normalize line breaks. Need this e.g. when the value is
// coming from a URL, which used platform line breaks.
nsLinebreakConverter::ConvertStringLineBreaks(defaultValue,
nsLinebreakConverter::eLinebreakAny, nsLinebreakConverter::eLinebreakContent);
ChildCount(nChildren);
// If a child exist we try to reuse it
if (nChildren > 0) {
nsCOMPtr<nsIContent> child;
nsCOMPtr<nsIDOMText> textNode;
// Strip only one leading LF if there is one (bug 40394)
if (0 == defaultValue.Find("\n", PR_FALSE, 0, 1)) {
defaultValue.Cut(0,1);
rv = ChildAt(0, *getter_AddRefs(child));
NS_ENSURE_SUCCESS(rv, rv);
textNode = do_QueryInterface(child);
if(textNode) {
rv = textNode->SetData(aDefaultValue);
NS_ENSURE_SUCCESS(rv, rv);
firstChildUsed = PR_TRUE;
}
}
nsGenericHTMLContainerFormElement::SetAttr(kNameSpaceID_HTML,
nsHTMLAtoms::defaultvalue,
defaultValue, PR_TRUE);
SetValue(defaultValue);
PRInt32 lastChild = firstChildUsed ? 1 : 0;
for (i = nChildren-1; i >= lastChild; i--) {
RemoveChildAt(i, PR_TRUE);
}
if (!firstChildUsed) {
nsCOMPtr<nsIContent> textContent;
rv = NS_NewTextNode(getter_AddRefs(textContent));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMText> textNode;
textNode = do_QueryInterface(textContent);
rv = textNode->SetData(aDefaultValue);
NS_ENSURE_SUCCESS(rv, rv);
AppendChildTo(textContent, PR_TRUE, PR_TRUE);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::InsertChildAt(nsIContent* aKid, PRInt32 aIndex,
PRBool aNotify, PRBool aDeepSetDocument)
{
nsresult rv;
rv = nsGenericHTMLContainerFormElement::InsertChildAt(aKid, aIndex, aNotify,
aDeepSetDocument);
if (!mValueChanged) {
Reset();
}
return rv;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex,
PRBool aNotify, PRBool aDeepSetDocument)
{
nsresult rv;
rv = nsGenericHTMLContainerFormElement::ReplaceChildAt(aKid, aIndex, aNotify,
aDeepSetDocument);
if (!mValueChanged) {
Reset();
}
return rv;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::AppendChildTo(nsIContent* aKid, PRBool aNotify,
PRBool aDeepSetDocument)
{
nsresult rv;
rv = nsGenericHTMLContainerFormElement::AppendChildTo(aKid, aNotify,
aDeepSetDocument);
if (!mValueChanged) {
Reset();
}
return rv;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
{
nsresult rv;
rv = nsGenericHTMLContainerFormElement::RemoveChildAt(aIndex, aNotify);
if (!mValueChanged) {
Reset();
}
return rv;
}
NS_IMETHODIMP
nsHTMLTextAreaElement::StringToAttribute(nsIAtom* aAttribute,
const nsAReadableString& aValue,
@ -747,10 +860,17 @@ nsHTMLTextAreaElement::GetControllers(nsIControllers** aResult)
nsresult
nsHTMLTextAreaElement::Reset()
{
nsAutoString resetVal;
GetDefaultValue(resetVal);
nsresult rv = SetValue(resetVal);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv;
// If the frame is there, we have to set the value so that it will show up.
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
if (formControlFrame) {
nsAutoString resetVal;
GetDefaultValue(resetVal);
rv = SetValue(resetVal);
NS_ENSURE_SUCCESS(rv, rv);
formControlFrame->OnContentReset();
}
SetValueChanged(PR_FALSE);
return NS_OK;
}

View File

@ -803,7 +803,7 @@ MakeContentObject(nsHTMLTag aNodeType,
nsIDOMHTMLFormElement* aForm,
nsIWebShell* aWebShell,
nsIHTMLContent** aResult,
const nsString* aContent = nsnull,
const nsAString* aSkippedContent = nsnull,
PRBool aInsideNoXXXTag = PR_FALSE);
@ -843,14 +843,15 @@ HTMLContentSink::CreateContentObject(const nsIParserNode& aNode,
}
if (NS_SUCCEEDED(rv)) {
// Make the content object
// XXX why is textarea not a container?
nsAutoString content;
if (eHTMLTag_textarea == aNodeType) {
content.Assign(aNode.GetSkippedContent());
// XXX if the parser treated the text in a textarea like a normal textnode
// we wouldn't need to do this.
const nsAString* skippedContent = nsnull;
if (aNodeType == eHTMLTag_textarea) {
skippedContent = &aNode.GetSkippedContent();
}
// Make the content object
rv = MakeContentObject(aNodeType, nodeInfo, aForm, aWebShell,
aResult, &content, !!mInsideNoXXXTag);
aResult, skippedContent, !!mInsideNoXXXTag);
PRInt32 id;
mDocument->GetAndIncrementContentID(&id);
@ -991,7 +992,7 @@ MakeContentObject(nsHTMLTag aNodeType,
nsIDOMHTMLFormElement* aForm,
nsIWebShell* aWebShell,
nsIHTMLContent** aResult,
const nsString* aContent,
const nsAString* aSkippedContent,
PRBool aInsideNoXXXTag)
{
nsresult rv = NS_OK;
@ -1218,23 +1219,32 @@ MakeContentObject(nsHTMLTag aNodeType,
rv = NS_NewHTMLTableCellElement(aResult, aNodeInfo);
break;
case eHTMLTag_textarea:
//if (nsHTMLElementFactory::mUseXBLForms)
// rv = NS_NewHTMLSpanElement(aResult, aNodeInfo);
//else {
rv = NS_NewHTMLTextAreaElement(aResult, aNodeInfo);
// XXX why is textarea not a container. If it were, this code would not be necessary
// If the text area has some content, set it
if (aContent && (aContent->Length() > 0)) {
nsIDOMHTMLTextAreaElement* taElem;
rv = (*aResult)->QueryInterface(NS_GET_IID(nsIDOMHTMLTextAreaElement), (void **)&taElem);
if ((NS_OK == rv) && taElem) {
taElem->SetDefaultValue(*aContent);
NS_RELEASE(taElem);
rv = NS_NewHTMLTextAreaElement(aResult, aNodeInfo);
// XXX if the parser treated the text in a textarea like a normal textnode
// we wouldn't need to do this.
// If the text area has some content, set it
if (aSkippedContent && (!aSkippedContent->IsEmpty())) {
// Strip only one leading newline if there is one (bug 40394)
nsString::const_iterator start, end;
aSkippedContent->BeginReading(start);
aSkippedContent->EndReading(end);
if (*start == nsCRT::CR) {
++start;
if (start != end && *start == nsCRT::LF) {
++start;
}
}
if (!aInsideNoXXXTag)
SetForm(*aResult, aForm);
//}
else if (*start == nsCRT::LF) {
++start;
}
nsCOMPtr<nsIDOMHTMLTextAreaElement> ta(do_QueryInterface(*aResult));
if (ta) {
ta->SetDefaultValue(Substring(start, end));
}
}
if (!aInsideNoXXXTag)
SetForm(*aResult, aForm);
break;
case eHTMLTag_title:
rv = NS_NewHTMLTitleElement(aResult, aNodeInfo);
@ -2224,14 +2234,12 @@ SinkContext::FlushText(PRBool* aDidFlush, PRBool aReleaseLast)
FlushText(aDidFlush, aReleaseLast);
}
else {
nsCOMPtr<nsIDOMCharacterData> cdata = do_QueryInterface(mLastTextNode, &rv);
if (NS_SUCCEEDED(rv)) {
CBufDescriptor bd(mText, PR_TRUE, mTextSize+1, mTextLength);
bd.mIsConst = PR_TRUE;
nsAutoString str(bd);
rv = cdata->AppendData(str);
nsCOMPtr<nsIDOMCharacterData> cdata(do_QueryInterface(mLastTextNode));
if (cdata) {
rv = cdata->AppendData(Substring(mText, mText + mTextLength));
mLastTextNodeSize += mTextLength;
mTextLength = 0;
didFlush = PR_TRUE;

View File

@ -730,9 +730,7 @@ nsXMLContentSink::OpenContainer(const nsIParserNode& aNode)
result = NS_CreateHTMLElement(getter_AddRefs(htmlContent), nodeInfo, PR_TRUE);
content = do_QueryInterface(htmlContent);
if (tagAtom.get() == nsHTMLAtoms::textarea) {
mTextAreaElement = do_QueryInterface(htmlContent);
} else if (tagAtom.get() == nsHTMLAtoms::style) {
if (tagAtom.get() == nsHTMLAtoms::style) {
mStyleElement = htmlContent;
} else if (tagAtom.get() == nsHTMLAtoms::base) {
if (!mBaseElement) {
@ -861,12 +859,6 @@ nsXMLContentSink::CloseContainer(const nsIParserNode& aNode)
}
mInTitle = PR_FALSE;
}
} else if (tagAtom.get() == nsHTMLAtoms::textarea) {
if (mTextAreaElement) {
mTextAreaElement->SetDefaultValue(mTextareaText);
mTextAreaElement = nsnull;
mTextareaText.Truncate();
}
} else if (tagAtom.get() == nsHTMLAtoms::style) {
if (mStyleElement) {
result = ProcessSTYLETag(aNode);
@ -1019,8 +1011,6 @@ nsXMLContentSink::AddCDATASection(const nsIParserNode& aNode)
const nsAReadableString& text = aNode.GetText();
if (mInTitle) {
mTitleText.Append(text);
} else if (mTextAreaElement) {
mTextareaText.Append(text);
} else if (mStyleElement) {
mStyleText.Append(text);
}
@ -1505,8 +1495,6 @@ nsXMLContentSink::AddText(const nsAReadableString& aString)
if (mInTitle) {
mTitleText.Append(aString);
} else if (mTextAreaElement) {
mTextareaText.Append(aString);
} else if (mStyleElement) {
mStyleText.Append(aString);
}

View File

@ -217,9 +217,7 @@ protected:
nsString mRef; // ScrollTo #ref
nsString mTitleText;
nsString mTextareaText;
nsCOMPtr<nsIDOMHTMLTextAreaElement> mTextAreaElement;
nsCOMPtr<nsIHTMLContent> mStyleElement;
nsCOMPtr<nsIHTMLContent> mBaseElement;
nsCOMPtr<nsIHTMLContent> mMetaElement;