Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

Prototype $$ method fails due to missing className on DOMNode

#30

Prototype's $$("class") method, which is akin to jQuery's $(".class") method, is failing because it's traversing the DOM and expecting each node to have a defined, non-null class name value. However, DOMNode has no "className" value.

Reported by larry.karnowski (at gmail) · February 1st, 2009 @ 06:19 AM

State: resolved
Milestone: 1.0 Release
Assigned to: Thatcher Thatcher

Activity

  1. larry.karnowski (at gmail)
    larry.karnowski (at gmail)

    I've added a Prototype compatibility test and a patch for this on my GitHub fork. Here are the commits:

    Prototype compat test: http://github.com/Lawjoskar/env-...

    Patch: http://github.com/Lawjoskar/env-...

    February 1st, 2009 @ 06:27 AM

  2. Thatcher
    Thatcher
    • Milestone set to 1.0 Release
    • State changed from new to open
    • Assigned user set to Thatcher

    Thanks Larry.

    I'm confused about why the correct place is on the DOMNode, since most dom nodes in firebug don't have this property. Try examining the childNodes property of an average element you'll see that text nodes and attributes dont have this, just elements.

    It is a property of the HTMLElement but maybe some element is being searched that was not created as a dom element and not an html element.

    Let's put the patch there first and see if that corrects the issue. Can you explain the error more specifically.

    PS I might borrow your prototype compat test to get myself started here.

    Thatcher

    February 16th, 2009 @ 08:58 AM

  3. Thatcher
    Thatcher

    Ok I think the relavant code from prototype is

    
    var nodes = $(element).getElementsByTagName('*');
        className = ' ' + className + ' ';
    
        for (var i = 0, child, cn; child = nodes[i]; i++) {
          if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
              (classNames && classNames.all(function(name) {
                return !name.toString().blank() && cn.include(' ' + name + ' ');
              }))))
            elements.push(Element.extend(child));
        }
        return elements;
      };
    

    so it is iterating what should be a list of html elements so having className on the html Element interface should be enough. I need to double check but I think the actual problem may be in the getElementByTagName code. for the case where the name is '*'.

    February 16th, 2009 @ 09:31 AM

  4. Thatcher
    Thatcher

    Yeah so the cleaner patch in this case is to getElementsByTagNameRecursive

    Before we had:

    
    if (elem.nodeType == DOMNode.ELEMENT_NODE || elem.nodeType == DOMNode.DOCUMENT_NODE) {
        
            if(elem.nodeName.toUpperCase() == tagname.toUpperCase() || (tagname == "*")){
                __appendChild__(nodeList, elem);               // add matching node to nodeList
            }
    

    This put the Document Node in the list. ;(

    So I changed it to this:

    
    if (elem.nodeType == DOMNode.ELEMENT_NODE || elem.nodeType == DOMNode.DOCUMENT_NODE) {
        
            if(elem.nodeType !== DOMNode.DOCUMENT_NODE && 
                ((elem.nodeName.toUpperCase() == tagname.toUpperCase()) || 
                    (tagname == "*")) ){
                __appendChild__(nodeList, elem);               // add matching node to nodeList
            }
    

    so it'll only add elements to the list but still allow recursion on the docuement node.

    You test passes then!

    I'll close this ticket when I commit.

    February 16th, 2009 @ 09:42 AM

  5. Thatcher

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.