#209 ✓invalid
Luis Fernando Rocha

Problem with _counted in IE

Reported by Luis Fernando Rocha | July 8th, 2008 @ 08:23 PM

I found nothing on _counted='undefined' out on the web that would help me. When I searched through the Prototype code, I noticed that unmark was setup as follows:

unmark: function(nodes) {
 for (var i = 0, node; node = nodes[i]; i++)
  node._countedByPrototype = undefined;
 return nodes;
}

so I changed it to:

unmark: function(nodes) {
 for (var i = 0, node; node = nodes[i]; i++)
  node._countedByPrototype = false;
 return nodes;
}

and it worked!! It now works on IE without a problem, and didn't break Firefox.

Found that undefined was not defined anywhere.

Comments and changes to this ticket

  • John-David Dalton

    John-David Dalton July 7th, 2008 @ 11:43 PM

    • Tag set to needs_failing_test_case, needs_patch, needs_tests

    IE has its own fork later on in the code:

    if (Prototype.Browser.IE) {
      Object.extend(Selector.handlers, {
        // IE returns comment nodes on getElementsByTagName("*").
        // Filter them out.
        concat: function(a, b) {
          for (var i = 0, node; node = b[i]; i++)
            if (node.tagName !== "!") a.push(node);
          return a;
        },
    
        // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
        unmark: function(nodes) {
          for (var i = 0, node; node = nodes[i]; i++)
            node.removeAttribute('_countedByPrototype');
          return nodes;
        }
      });
    }
    

    Check out:

    http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Properties

  • John-David Dalton

    John-David Dalton July 7th, 2008 @ 11:43 PM

    • State changed from “new” to “invalid”
    • Tag changed from needs_failing_test_case, needs_patch, needs_tests to needs_failing_test_case
  • Luis Fernando Rocha

    Luis Fernando Rocha July 8th, 2008 @ 12:11 AM

    I tested with that code in place, but it wasn't working. It wasn't until I made the modification mentioned above that it worked.

  • John-David Dalton

    John-David Dalton July 8th, 2008 @ 12:18 AM

    What version of IE and what selector where you using?

  • Luis Fernando Rocha

    Luis Fernando Rocha July 8th, 2008 @ 12:45 AM

    IE 7.0.5730.13, Prototype 1.6.0.2, trying to up or down anything in a table.
    The problem seemed to be when the item I was looking for was within a TBODY tag,
    but not within a THEAD. I even had to switch from inputs to spans, 
    oh and had to use classes instead of ids 
    (i.e. switched from <input id="something"> to <span class="something">), 
    which still didn't work until I made the change mentioned above.
    
  • Luis Fernando Rocha

    Luis Fernando Rocha July 8th, 2008 @ 12:44 AM

    Here is what I had at one point, which is what made me look into the _counted issue. This is from the Microsoft Debugger. The id I added to see if it would work, but it didn't.

    <TBODY id=tbod _counted=\"undefined\"></TBODY></TABLE></TD></TR></TBODY>
    
  • John-David Dalton

    John-David Dalton July 8th, 2008 @ 12:46 AM

    _counted is totally different from the "_countedByPrototype" property that is set.

    I think the problem is something else.

  • Luis Fernando Rocha

    Luis Fernando Rocha July 8th, 2008 @ 04:27 PM

    I know it's not the same, but when I changed the code as above, from "node._countedByPrototype = undefined;" to "node._countedByPrototype = false;" the problem went away.

  • Juriy Zaytsev

    Juriy Zaytsev July 8th, 2008 @ 05:46 PM

    I'm still not following what the exact problem was. Would you mind explaining?

  • Luis Fernando Rocha

    Luis Fernando Rocha July 8th, 2008 @ 07:23 PM

    I am creating two devices (divs with class="device"). Within the div is a table with a thead and a tbody:

    <table class="paneListing" cellpadding="0" cellspacing="0" id="' + devices[i].id.replace('Container','') + '">
     <thead class="sort">
      <tr>
       <th id="headpatientName" onclick="oDevice.resort(this);" width="170" class="up">
        <div></div>Name</th>
       <th id="headpatientDOB" onclick="oDevice.resort(this);" width="90">
        <div></div>Birth Date</th>
       <th id="headlabdate" onclick="oDevice.resort(this);" width="75" >
        <div></div>Lab Date</th>
       <th id="headpatientID" onclick="oDevice.resort(this);" width="150">
        <div></div>Account Number</th>
       <th id="headalternateID" onclick="oDevice.resort(this);" width="170" >
        <div></div>Medical Record Number</th></tr>
     </thead>
     <tbody></tbody>
    </table>
    

    When I click on a th the oDevice.resort function is as follows:

    resort:function(container){
     var sortBy = container.up('.device').down('span.sort'),
      dir = container.up('.device').down('span.dir'),
      header = container.id.replace('head','');
     if(header == sortBy.innerHTML){
      container.removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName(dir.innerHTML == 1 ? 'up' : 'down');
      dir.innerHTML = dir.innerHTML	 == 1 ? 0 : 1;
     }else{
      container.up('.device').down('#head'+sortBy.innerHTML).removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName('up');
      sortBy.innerHTML = container.id.replace('head','');
      dir.innerHTML = 0;
     }
     this.populateDevice(container.up('.device'));
    }
    

    When I have line 3018 set as "node._countedByPrototype = undefined;" and there is only one row in tbody that says 'No results found', I get the error "Line: 120 Char: 3 Error: Object doesn't support this property or method Code: 0", but then when I click on View All and the tbody is populated with the result lines, I get the error message "Line: 126 Char: 4 Error: 'up(...).down(...)' is null or not an object Code: 0".

    The interesting part is that this only happens with the SECOND

    table. The first one works fine after the first error is shown.

    When I activate the Microsoft Script Editor, the error takes me to the first line of the resort function, highlighting the first var, sortBy. At this point I can't see the table yet. So I click on View All and then try resort again.

    When I click there I am taken to the Editor again and ... yesterday the tag was altered to show as

  • Juriy Zaytsev

    Juriy Zaytsev July 8th, 2008 @ 07:04 PM

    I don't see where you have a span with a "dir" className (as you're calling up('.device').down('span.dir'))

  • Luis Fernando Rocha

    Luis Fernando Rocha July 8th, 2008 @ 07:27 PM

    Sorry. Here are the calls I'm making.

    for(var i=0;i<devices.length;i++){
      devices[i].down('.content')
        .update('<div class="deviceOption tabs"><a href="javascript: void 0;">New</a> <a href="javascript: void 0;">Sent</a> <a
    href="javascript: void 0;">Repeats</a> <a href="javascript: void 0;">Controls</a></div><div class="deviceOption" style="clear: both;"><a href="javascript: void 0;" onclick="oDevice.toggleAll(\''+devices[i].id.replace('Container','')+'\');" id="viewLink">View 
    All</a>&nbsp;&nbsp;<a href="javascript: void 0;" onclick="oDevice.populateDevice($(\''+devices[i].id+'\'));">Refresh</a></div><div class="deviceOption spinner" style="display: none;"></div><table class="paneListing" cellpadding="0" cellspacing="0" id="'+devices
    [i].id.replace('Container','')+'"><thead class="sort"><tr><th id="headpatientName" onclick="oDevice.resort(this);" width="170"
    class="up"><div></div>Name</th><th id="headpatientDOB" onclick="oDevice.resort(this);" width="90"><div></div>Birth Date</th><th
    id="headlabdate" onclick="oDevice.resort(this);" width="75" ><div></div>Lab Date</th><th id="headpatientID" onclick="oDevice.resort(this);"
    width="150"><div></div>Account Number</th><th id="headalternateID" onclick="oDevice.resort(this);" width="170" ><div></div>Medical Record 
    Number</th></tr></thead><tbody></tbody></table>');
    
      devices[i].down('tbody').insert({top:'<tr class="top" style="display: none;"><td><span class="index">0</span><span class="sort">patientName</span><span class="dir">0</span><span class="all">0</span><span class="status">new</span></td></tr>'});
    
      oDevice.populateDevice(devices[i]);
    
  • John-David Dalton

    John-David Dalton July 8th, 2008 @ 08:22 PM

    Use the formatting help

    I have corrected your previous posts.

  • Luis Fernando Rocha

    Luis Fernando Rocha July 9th, 2008 @ 06:51 PM

    Ok. After much fiddling around (and near giving up on IE clients -- YEAH RIGHT!!!), here's how I had to rewrite the function and it now works, even with line 3018 set back to

    node._countedByPrototype = undefined;

    :

    resort:function(container){
     var columns = {'patientName':0, 'patientDOB':1, 'labdate':2, 'patientID':3, 'alternateID':4};
     var sortBy = Element.up(container,'.device').down('span',1);
     var dir = container.up('.device').down('span.dir');
     var header = container.id.replace('head','');
     if(header == sortBy.innerHTML){
      container.removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName(dir.innerHTML == 1 ? 'up' : 'down');
      dir.innerHTML = dir.innerHTML	 == 1 ? 0 : 1;
     }else{
      Element.up(container, '.device').down('th', columns[sortBy.innerHTML]).removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName('up');
      sortBy.innerHTML = container.id.replace('head','');
      dir.innerHTML = 0;
     }
     this.populateDevice(container.up('.device'));
    

    it's just bothersome how messy I have to make my code just so it'll work on IE. :)

  • John-David Dalton

    John-David Dalton July 9th, 2008 @ 06:58 PM

    I still have no idea what your issue was.

    The code you mentioned initially was never touched by IE.

    I can only assume this is a user error.

    Would you please post the code you initially tried that failed for you.

  • Luis Fernando Rocha

    Luis Fernando Rocha July 9th, 2008 @ 07:15 PM

    Here is how it works. I have a table with a header row enclosed in a thead tag. The device div is populated by the following:

    for(var i=0;i<devices.length;i++){
      devices[i].down('.content')
        .update('<div class="deviceOption tabs"><a href="javascript: void 0;">New</a> <a href="javascript: void 0;">Sent</a> <a
    href="javascript: void 0;">Repeats</a> <a href="javascript: void 0;">Controls</a></div><div class="deviceOption" style="clear: both;"><a href="javascript: void 0;" onclick="oDevice.toggleAll(\''+devices[i].id.replace('Container','')+'\');" id="viewLink">View 
    All</a>&nbsp;&nbsp;<a href="javascript: void 0;" onclick="oDevice.populateDevice($(\''+devices[i].id+'\'));">Refresh</a></div><div class="deviceOption spinner" style="display: none;"></div><table class="paneListing" cellpadding="0" cellspacing="0" id="'+devices
    [i].id.replace('Container','')+'"><thead class="sort"><tr><th id="headpatientName" onclick="oDevice.resort(this);" width="170"
    class="up"><div></div>Name</th><th id="headpatientDOB" onclick="oDevice.resort(this);" width="90"><div></div>Birth Date</th><th
    id="headlabdate" onclick="oDevice.resort(this);" width="75" ><div></div>Lab Date</th><th id="headpatientID" onclick="oDevice.resort(this);"
    width="150"><div></div>Account Number</th><th id="headalternateID" onclick="oDevice.resort(this);" width="170" ><div></div>Medical Record 
    Number</th></tr></thead><tbody></tbody></table>');
      devices[i].down('tbody').insert({top:'<tr class="top" style="display: none;"><td><span class="index">0</span><span class="sort">patientName</span><span class="dir">0</span><span class="all">0</span><span class="status">new</span></td></tr>'});
      oDevice.populateDevice(devices[i]);
    

    When I click on the th tag (whether Name, Birth Date, etc), it calls the resort function of the current oDevice.

    Before:

    resort:function(container){
     var sortBy = container.up('.device').down('span.sort'),
      dir = container.up('.device').down('span.dir'),
      header = container.id.replace('head','');
     if(header == sortBy.innerHTML){
      container.removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName(dir.innerHTML == 1 ? 'up' : 'down');
      dir.innerHTML = dir.innerHTML	 == 1 ? 0 : 1;
     }else{
      container.up('.device').down('#head'+sortBy.innerHTML).removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName('up');
      sortBy.innerHTML = container.id.replace('head','');
      dir.innerHTML = 0;
     }
     this.populateDevice(container.up('.device'));
    }
    

    What was happening here was that when it got to the

     var sortBy = container.up('.device').down('span.sort'),
    

    it would tell me that the up(...).down(...) was not valid. I inspected the code returned by Microsoft Script Editor and found

    _counted="undefined"
    

    added to the tbody tags.

    I changed line 3018 in prototype.js to

     node._countedByPrototype = false;
    

    and it seemed to fix the problem...until today. So I went back to rewrite the function and settled on the function below:

    After:

    resort:function(container){
     var columns = {'patientName':0, 'patientDOB':1, 'labdate':2, 'patientID':3, 'alternateID':4};
     var sortBy = Element.up(container,'.device').down('span',1);
     var dir = container.up('.device').down('span.dir');
     var header = container.id.replace('head','');
     if(header == sortBy.innerHTML){
      container.removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName(dir.innerHTML == 1 ? 'up' : 'down');
      dir.innerHTML = dir.innerHTML	 == 1 ? 0 : 1;
     }else{
      Element.up(container, '.device').down('th', columns[sortBy.innerHTML]).removeClassName(dir.innerHTML == 1 ? 'down' : 'up');
      container.addClassName('up');
      sortBy.innerHTML = container.id.replace('head','');
      dir.innerHTML = 0;
     }
     this.populateDevice(container.up('.device'));
    

    The deal with this is that I could call

    element.up('something').down('somethingelse');
    

    in EVERY browser except IE. And the kicker is that it would work fine on the first 'div.device' on the page. The problem was only with any subsequent 'div.device'.

  • Luis Fernando Rocha
  • Juriy Zaytsev

    Juriy Zaytsev July 9th, 2008 @ 10:05 PM

    Luis,

    if you could narrow the problem down to an exact expression that's causing it, we will be happy to look into it.

  • Luis Fernando Rocha

    Luis Fernando Rocha July 9th, 2008 @ 09:58 PM

    I'm not sure how else to explain. It was originally only happening when I clicked on the TH to resort, which would give me the error "up(...).down(...)" doesn't exist. As I've added more code to my app today, it's sprung up more, and it ONLY happens on the subsequent divs in my app, not on the first one. I'm having to use the

    Element.up(element, expression, index)
    Element.down(element, expression, index)
    

    calls, and I have to figure out the exact index of the tag I'm looking for, and I can't provide ids or classes in the expression, only tags (i.e. up(element, 'span', 3), not element.up('span.option') or element.up('div#main')).

    But this only applies to IE, and to the second div. You can see the layout in the attached image. Each device (labeled 'Browsville - Main' and 'Harlingen - Central') are within a div. The contents of the device div are from the function above in an earlier post (the for loop). Let me know how else I can explain.

  • 5letters

    5letters July 16th, 2008 @ 08:04 AM

    I have seen a problem with IE6 and IE7 when using select() on a table element and I suspect it is related to the issue reported in this thread.

    If you perform select('td') on a table element once, it works fine. When perform the second time select('td') fails to return an element array because _counted="undefied" was added to td. select('tr') or any other element within the table still works.

  • 5letters

    5letters July 16th, 2008 @ 08:33 AM

    Okay, the problem is not unqiue to 'td' or table. The root cause seems to be within the unmark function(). A simple one-line change would fix it.

    from: node._counted = undefined;

    to: node.removeAttribute('_counted');

    Tested on IE5, IE6, FF2 and FF3.

    HTH.

  • 5letters

    5letters July 16th, 2008 @ 08:34 AM

    typo: tested on IE6, IE7, FF2 and FF3.

  • John-David Dalton

    John-David Dalton July 16th, 2008 @ 02:46 PM

    This is a bug in Prototype 1.5.x

    You should really consider upgrading to 1.6.0.2

  • Luis Fernando Rocha

    Luis Fernando Rocha July 16th, 2008 @ 02:51 PM

    As noted on my post July 7th, 2008 @ 05:45 PM, I'm using IE 7.0.5730.13 and Prototype 1.6.0.2 when I see this problem.

  • John-David Dalton

    John-David Dalton July 16th, 2008 @ 03:04 PM

    Right but your issue isn't related to the _count property because its never set in the code (doesnt exist in 1.6.0.2).

    It may be related to tables though.

  • John-David Dalton

    John-David Dalton July 16th, 2008 @ 03:48 PM

    @Luis Fernando Rocha - one issue I see with your code is you have:

    onclick="oDevice.resort(this); inside your TH.
    

    That sends a possibly unextended element to oDevice.resort().

    Inside your resort method you should have

    container = $(container)
    

    Then all of your container.up and container.down stuff will work.

  • 5letters

    5letters July 16th, 2008 @ 07:30 PM

    John-David,

    the _counted issue exists in 1.6.0.1 which is what we use. and 1.6.0.2 simply change the name from _counted to _countedByPrototype but the bug is still there. it only takes one a minute to write a few lines of code to repro the problem.

  • John-David Dalton

    John-David Dalton July 16th, 2008 @ 07:49 PM

    Good to know (I didn't check 1.6.0.1, because it was quickly replaced with 1.6.0.2).

    In 1.6.0.2 it does more than change the name to "_countedByPrototype".

    It also forks for IE (further down in the code) and doesn't set the property to undefined, but rather removed the attribute via line 3366:

    node.removeAttribute('_countedByPrototype');
    

    Before I posted my previous comments I did do a simple test and it seemed to pass in 1.6.0.2

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    	"http://www.w3.org/TR/html4/loose...">
    <html>
    <head>
    <title>Test</title>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    
    <script src="prototype.js" type="text/javascript"></script>
    
    <script type="text/javascript">
    document.observe('dom:loaded', function(){
       alert($('foo').select('td'));
       alert($('foo').select('td'));
    });
    
    </script>
    </head>
    <body >
    <table id="foo">
      <tbody>
        <tr><td>hi</td><td>bye</td></tr>
        <tr><td>hi</td><td>bye</td></tr>
      </tbody>
    </table>
    </body>
    </html>
    
  • 5letters

    5letters July 16th, 2008 @ 07:57 PM

    Sorry about that. I only took a quick look at 1.6.0.2 and missed the change you mentioned. We will try to upgrade to 0.2. The reason 0.1 is still in use is because that is the version bundled with the latest release of Scriptaculous.

  • John-David Dalton

    John-David Dalton July 16th, 2008 @ 08:00 PM

    Ya 1.6.0.2 works fine with Scriptaculous 1.8.1

  • Yaffle

    Yaffle May 25th, 2009 @ 06:55 PM

    last commit:
    Do not browser sniff when forking unmark function in selector suite.
    Instead use a proper test - PROPERTIES_ATTRIBUTES_MAP.

    http://github.com/sstephenson/prototype/commit/cebf7d673b3a467bb056...

    It works in Opera 9.62?

  • Juriy Zaytsev

    Juriy Zaytsev May 26th, 2009 @ 04:24 AM

    @Yaffle

    What works in Opera 9.62?

  • Yaffle

    Yaffle May 26th, 2009 @ 10:08 AM

    var PROPERTIES_ATTRIBUTES_MAP = (function(){
    0
    +        var el = document.createElement('div'), 
    0
    +            isBuggy = false,
    0
    +            propName = '_countedByPrototype',
    1
    +            value = 'x'
    0
    +        el[propName] = value;
    0
    +        isBuggy = (el.getAttribute(propName) === value);
    0
    +        el = null;
    0
    +        return isBuggy;
    0
    +      });
    

    missing "()" at the end.

  • Tobie Langel

    Tobie Langel July 24th, 2009 @ 03:40 AM

    • Tag changed from needs_failing_test_case to needs:failing_testcase

    [not-tagged:"needs_failing_test_case" tagged:"needs:failing_testcase" bulk edit command]

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

The Prototype JavaScript library.

Shared Ticket Bins

Attachments

Pages