Menu

#1993 Javascript: DIV.innerHTML adding operation bug

2.33
closed
RBRi
javascript (30)
1
2018-10-18
2018-10-16
No

In real browser, when I add the inner html of one div A to another div B, the height of B is also added by the height of A. But in htmlunit, it doesn't. The test code to reproduce:

    public static void testDivAdd() throws Exception
    {
        List<String> alerts = new ArrayList<>();
        WebClient wc=new WebClient();
        wc.setAlertHandler(new CollectingAlertHandler(alerts));
        wc.getPage(HtmlUnitTest.class.getResource("divadd.html"));
        System.out.println(alerts.toString());
    }

The content of the divadd.html:

<html>
<head>
    <title>test</title>
</head>

<body>
<div id="div1" style="height: 18px">
    aaa<br/>
</div>
<div id="templayer" ></div>

<script language="JavaScript">
function init(){ 
    templayer.innerHTML=""; 
    alert("before "+templayer.offsetHeight);
    templayer.innerHTML+=div1.innerHTML; 
    alert("after "+templayer.offsetHeight);
}
document.body.onload=init;
</script>
</body>
</html>

Discussion

  • Rural Hunter

    Rural Hunter - 2018-10-16

    I looked a bit more. The result of this simple code is different if I called getOffsetHeight() before in HTMLElement.setInnerHTML():

    templayer.innerHTML="aaa"
    alert(templayer.offsetHeight);
    
    public void setInnerHTML(final Object value) {
            System.out.println("before set offsetHight="+getOffsetHeight());//this line makes different result
            super.setInnerHTML(value);
    

    If I called getOffsetHeight() before setInnerHTML(), the result is 0. If I remove that line, the result is good.
    I guess there is something wrong in getOffsetHeight() which may affects the behavior.

     

    Last edit: Rural Hunter 2018-10-16
  • Rural Hunter

    Rural Hunter - 2018-10-16

    The problem is in ComputedCSSStyleDeclaration.getCalculatedHeight() which uses the cached height property and it seems there is no way to reset it if the content of the element is changed. I commented the part to use the cache and it fixed the issue. I guess there should be better fix but I don't have enough understanding of this class so I leave it for you. :)

    private int getCalculatedHeight() {
    //        if (height_ != null) {
    //            return height_.intValue();
    //        }
    
            int height = getEmptyHeight();
            if (height == 0) {
                height_ = Integer.valueOf(0);
                return 0;
            }
    
     
  • Rural Hunter

    Rural Hunter - 2018-10-16

    It seems the next part of the code also needs to be commented out if there is child node involved:

    private int getCalculatedHeight() {
    //        if (height_ != null) {
    //            return height_.intValue();
    //        }
    
            int height = getEmptyHeight();
    //        if (height == 0) {
    //            height_ = Integer.valueOf(0);
    //            return 0;
    //        }
    
            if (super.getHeight().isEmpty()) {
                final int contentHeight = getContentHeight();
                if (contentHeight > 0) {
                    height = contentHeight;
                }
            }
    
            height_ = Integer.valueOf(height);
            return height;
        }
    
     
  • RBRi

    RBRi - 2018-10-17
    • status: open --> closed
     
  • RBRi

    RBRi - 2018-10-17

    Have added the cache cleanup and a unit test.

    Thanks for reporting and the detailed analysis

     

    Last edit: RBRi 2018-10-17
  • Rural Hunter

    Rural Hunter - 2018-10-18

    Thanks. I pulled the code and it resolved the issue partially. There is still problem if the div contains children. For example, if the div above changed from

    <div id="div1" style="height: 18px">
        aaa<br/>
    </div>
    

    to

    <div id="div1" style="height: 18px">
        <iframe height="360" src="http://...."></iframe>
    </div>
    

    This part of code in ComputedCSSStyleDeclaration.getCalculatedHeight() won't calculate the size of children if the height of the div itself(EmptyHeight) is 0:

                        int height = getEmptyHeight();
    //        if (height == 0) {
    //            height_ = Integer.valueOf(0);
    //            return 0;
    //        }
    
     
  • RBRi

    RBRi - 2018-10-18
    • status: closed --> accepted
     
  • RBRi

    RBRi - 2018-10-18

    I guess you second case is not related to the innerHtml call. If yes please open a new issue for this.

     
  • Rural Hunter

    Rural Hunter - 2018-10-18

    I agree. this looks more like a single element size calculation problem. I will try to make an independent test case and open a new issue.

     
  • Rural Hunter

    Rural Hunter - 2018-10-18

    I created #1997

     
  • RBRi

    RBRi - 2018-10-18
    • status: accepted --> closed
     
  • RBRi

    RBRi - 2018-10-18

    Thanks

     

Log in to post a comment.