Closed Bug 3394 Opened 26 years ago Closed 26 years ago

nsIDOMNode::GetNodeValue(nsString& aNodeValue) doesn't return current value of text fields

Categories

(Core :: DOM: Core & HTML, defect, P2)

x86
Windows NT
defect

Tracking

()

VERIFIED WORKSFORME

People

(Reporter: paul, Assigned: pollmann)

Details

Attachments

(1 file)

Note that this bug can not be reproduced (to the best of my knowledge) via
JavaScript --- it's a problem with the C++ API's nsIDOMNode interface.

1. Modify the viewer.exe so that, upon a menu selection, it walks thru the DOM,
beginning at the root of the currently loaded document, using the nsIDOMNode
interface.  When a node is found whose name (as returned by
nsIDOMNode::GetNodeName(nsString& aNodeName)) is "input", retrieve it's
attributes (using nsIDOMNode::GetAttributes(nsIDOMNamedNodeMap** aAttributes)).
Examine each attribute until you find one whose name (again as returned by
nsIDOMNode::GetNodeName(nsString& aNodeName) is "value".  Retrieve this
attribute's value (via nsIDOMNode::GetNodeValue(nsString& aNodeValue)) and
display it.

2. Have this modified viewer display the following form:

<html>
<body>

<form name="form1">
<input type=text name="text1" value="hello">
</form>

</body>
</html>


3. Make the new menu selection --- you should see "hello" as expected.

4. Now change the contents of the text field by typing into it and make the menu
selection again --- it still shows "hello" which is not as expected.

Shouldn't the node's value reflect the current value (contents) of the text
field?
Assignee: karnaze → pollmann
QA Contact: 4110 → 4015
Reassigning bug to gerardok@netscape.com
Status: NEW → ASSIGNED
Paul, could you add the diff you used to the bug report, it would save a lot of
time...
Per Eric's request, here's the code that walks the DOM (if inserting this here
made a big mess, let me know and I'll email to someone as an attachment).  It
will reproduce the error if inserted in the viewer from the March 5th build,
but I haven't tried it in anything more recent.  The steps to install/execute
the code (give or take a few declarations) are as follows:

1. Save the following html to a file named DOMBug1.html in the
mozilla/dist/.../samples subdirectory (e.g.
"mozilla\dist\WIN32_O.OBJ\bin\res\samples\DOMBug1.html").  So that viewer's
output is most readable, plz put it all on the same line:

   <html><body><form><input type=text name="text1"
value="hello"></form></body></html>

2. Modify nsViewerApp.cpp so that nsViewerApp's constructor assigns this file
as the startup URL.

   nsViewerApp::nsViewerApp()
   {
      NS_INIT_REFCNT();

      //  char * text = PR_GetEnv("NGLAYOUT_HOME");
      //  mStartURL = text ? text : "resource:/res/samples/test0.html";
      mStartURL = "resource:/res/samples/DOMBug1.html";
      ...
   }

3. Modify nsBrowserWindow.h, declaring the following as a method of
nsBrowserWindow:

   nsresult jpmGetRootContent(nsIContent** ppContent);

4. Modify nsBrowserWindow.cpp, supplying the following definition for the above:

   nsresult nsBrowserWindow::jpmGetRootContent(nsIContent** ppContent)
   {
      nsresult ret = NS_ERROR_FAILURE;
      if (nsnull != mWebShell) {
         nsIContentViewer* pCViewer;
         mWebShell->GetContentViewer(&pCViewer);   // get content viewer of web
shell
         if (nsnull != pCViewer) {
            nsIDocumentViewer* pDViewer;
            if (NS_OK == pCViewer->QueryInterface(kIDocumentViewerIID,
                            (void**) &pDViewer)) {   // get document viewer of
content viewer
               nsIDocument* pDoc;
               pDViewer->GetDocument(pDoc);   // get document of document viewer
               if (nsnull != pDoc) {
                  (*ppContent) = pDoc->GetRootContent();
                  if ((*ppContent) != nsnull) {
                     ret = NS_OK;
                  }
                  NS_RELEASE(pDoc);
               }
               NS_RELEASE(pDViewer);
            }
            NS_RELEASE(pCViewer);
         }
      }
     return ret;
   }


5. Add the following declarations/definitions somewhere near the top of
nsBrowserWindow.cpp:

   static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID);

   #include "nsIDOMHTMLFormElement.h"
   static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);

   #include "nsIDOMHTMLCollection.h"

   #include "nsIDOMNamedNodeMap.h"

   #include "nsIDOMHTMLInputElement.h"
   static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID);

   #include "nsIDOMHTMLSelectElement.h"
   static NS_DEFINE_IID(kIDOMHTMLSelectElementIID,
NS_IDOMHTMLSELECTELEMENT_IID);

   #include "nsIDOMHTMLTextAreaElement.h"
   static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID,
NS_IDOMHTMLTEXTAREAELEMENT_IID);

   //---------------------------------------------------------------------
   static PRUint32 gNextMsgNum = 1;

   void print_msg(nsString Msg) {
      char* pMsg = Msg.ToNewCString();
      printf("\n%4d-> %s", gNextMsgNum++, pMsg);
      delete pMsg;
   }

   nsresult
   PrintDOM(nsIDOMNode* pNode, nsString Indent) {
      nsString Name, Value, Msg;

      // display current node's name and value
      Msg = Indent;
      Msg.Append("Node: Name = '");
      if (NS_OK == pNode->GetNodeName(Name)) {
         Msg.Append(Name);
      }
      Msg.Append("', Value = '");
      if (NS_OK == pNode->GetNodeValue(Value)) {
         Msg.Append(Value);
      }
      Msg.Append("'");
      print_msg(Msg);

      // NewIndent will be passed when PrintDOM is called recursively
      nsString NewIndent(Indent);
      NewIndent.Append("      ");

      // now display node's attributes
      nsIDOMNamedNodeMap* pAttributes = nsnull;
      if ((NS_OK == pNode->GetAttributes(&pAttributes)) && (pAttributes !=
nsnull)) {
         PRUint32 AttrCnt;
         if (NS_OK == pAttributes->GetLength(&AttrCnt)) {
            if (AttrCnt > 0) {
               Msg = Indent;
               Msg.Append("  Has ");
               Msg.Append(AttrCnt, 10);
               Msg.Append(" attribute(s):");
               print_msg(Msg);

               for(PRUint32 i = 0; i < AttrCnt; ++i) {
                  Msg = Indent;
                  Msg.Append("    Attr ");
                  Msg.Append(i+1, 10);
                  Msg.Append(":");
                  print_msg(Msg);

                  nsIDOMNode* pAttrNode;
                  pAttributes->Item(i, &pAttrNode);
                  PrintDOM(pAttrNode, NewIndent);
                  NS_IF_RELEASE(pAttrNode);
               }
            } else {
               Msg = Indent;
               Msg.Append("  Has NO attributes.");
               print_msg(Msg);
            }
         }
         NS_IF_RELEASE(pAttributes);
      } else {
         Msg = Indent;
         Msg.Append("  Has NO attributes.");
         print_msg(Msg);
      }

      // now display node's children (by calling this function recursively)
      PRBool HasChildren;
      pNode->HasChildNodes(&HasChildren);
      if (HasChildren) {
         Msg = Indent;
         Msg.Append("  Has at least 1 child:");
         print_msg(Msg);

         nsIDOMNode* pChildNode = nsnull;
         PRUint32 ChildNum = 0;
         nsresult ret = pNode->GetFirstChild(&pChildNode);
         while ((ret == NS_OK) && (pChildNode != nsnull)) {
            ++ChildNum;
            Msg = Indent;
            Msg.Append("    Child ");
            Msg.Append(ChildNum, 10);
            Msg.Append(":");
            print_msg(Msg);

            PrintDOM(pChildNode, NewIndent);

            nsIDOMNode* pSiblingNode = nsnull;
            ret = pChildNode->GetNextSibling(&pSiblingNode);
            NS_IF_RELEASE(pChildNode);
            pChildNode = pSiblingNode;
         }
         NS_IF_RELEASE(pChildNode);
      } else {
         Msg = Indent;
         Msg.Append("  Has NO children.");
         print_msg(Msg);
      }

      return NS_OK;
   }


6. Rather than add a new menu item, save a little work by replacing the
File\Open menu handler.  So, while still in nsBrowserWindow.cpp, replace the
definition of nsBrowserWindow::DoFileOpen() with the following:

   void
   nsBrowserWindow::DoFileOpen()
   {
      gNextMsgNum = 1;
      nsIContent* pRoot;
      if (NS_OK == jpmGetRootContent(&pRoot)) {
         nsIDOMNode* pNode;
         if (NS_OK == pRoot->QueryInterface(kIDOMNodeIID, (void**) &pNode)) {
            if (NS_OK != PrintDOM(pNode, "")) {
               printf("\nPrintDOM returned error");
            }
            NS_RELEASE(pNode);
         }
         NS_RELEASE(pRoot);
      }
   }



7. Build then execute the viewer.  It should automatically display DOMBug1.html.

8. Select the File\Open menu and examine the output sent to the console
window.  Note the line

   36->                   Node: Name = 'value', Value = 'hello'

9. Change the contents of the displayed form's text field to something other
than 'hello', then repeat step 8.  Line 36 still shows "Value = 'hello'"
This is excellent!  Thanks, I'll try to track this down.
I was able to reproduce this behavior.  Working on it...
Status: ASSIGNED → RESOLVED
Closed: 26 years ago
Resolution: --- → WORKSFORME
Ah ha...  Happily this is not a bug - it is another occurrence of
foo/defaultFoo confusion.  Let me explain.  Vidur, can you correct me if
I am wrong here?

A text input has an just one HTML attribute "value".

It has two DOM properties "value" and "defaultValue".
  The DOM's "value" property represents the current text of the the input.
  The DOM's "defaultValue" property represents the HTML attribute.

While their name is the same, the HTML attribute "value" is not directly
related to the DOM property "value".  Here's how it works:

When a web page is parsed and the content model is constructed, the
property of the HTML attribute "value" (in this case "hello") is set.
This string is retained in, and is accessible through, the DOM.  It is
saved in an unmodified state because it will be used later.  For example,
if a user clicks on a form's Reset button, the text box must be returned
to its original value. ("hello").

After the form is loaded, you can use the DOM methods to access this
stored "defaultValue".  In fact, if you crawl the DOM to view all of the
stored attributes, you will see this stored value.

What you are attempting to do is access the current value of the text
input at a given time.  This value is not stored in the DOM, but it is
accessible through the DOM.  When the DOM method GetValue() is invoked on
a text input node, the DOM queries the actual text widget itself for it's
current value.  Since it is never stored in the DOM, if you just walk
through the nodes of the DOM, you won't see it.

Here's a way to prove to yourself that the DOM is working - with your
modified Viewer application try using this html file:

<html><body><form><input type=text name="text1" value="hello"><input
type=button value="value" onclick="this.form.text1.value='foo'"><input
type=button value="defaultValue"
onclick="this.form.text1.defaultValue='foo'"></form></body></html>

Name it DomBug2.html or whatever.  Browse over to it, then try
File->Open.  Line 36 reads as it does before.  Click on the "value"
button.  This sets the DOM property "value" to "foo".  It will affect the
value displayed in the text field, but not the value stored in the DOM.
Try File->Open.  Line 36 reads "hello" even though the text field reads
"foo".

Now, click on the "defaultValue" button.  This sets the DOM "defaultValue"
property to "foo".  It updates the button text, and ALSO updates the HTML
attribute stored in the DOM.  Try File->Open.  This time you will see Line
36 reading "foo"!

Hope this helps.  If not, let me know.
Attached file Testcase
Status: RESOLVED → VERIFIED
Verified on 1999-07-13-18 build.
Component: HTML: Form Submission → DOM: Core & HTML
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: