Problem with :contains selector in IE8

2019-08-02 16:15发布

问题:

I'm working on the following selector in jQuery:

$("div[id^=WebPartWPQ]:has(table.ms-sitedirresultssort) td:contains(' : ')").closest('div')

In other words: select the div with ID starting with WebPartWPQ that has a table with class ms-sitedirresultssort that has a td containing the text :. At the end of this question is the HTML rendered by SharePoint.

The selector works perfectly under Firefox 3.5, however not under Internet Explorer 8. I'm testing by using the hide() function.

I've narrowed it down to the td:contains(' : ') part of the selector. Running $("td:contains(' : ')") in Firebug Lite dumps out a whole list of functions like something isn't valid. All the other selectors work fine in FB Lite.

I've tried using jQuery 1.3.2 and jQuery 1.4rc1 without success. Is this a bug in jQuery and if so is there a ticket for it (I can't find one)? Any ideas on how to best get around this?

HTML:

<div style="" helpmode="1" helplink="/_layouts/help.aspx" allowdelete="false" class="ms-WPBody"
    width="100%" id="WebPartWPQ4" haspers="false" webpartid="2ae67b12-82db-4238-8be9-cd4b39cbd15a">
    <table cellspacing="0" cellpadding="0" border="0" width="100%" xmlns:crwp="urn:schemas-microsoft-com:CategoryResultsWebPart"
        xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:x="http://www.w3.org/2001/XMLSchema"
        class="ms-sitedirresultssort">
        <tbody>
            <tr>
                <td width="100%" />
                <td nowrap="">
                    <a href="#title">Sort by Title </a><span>| </span><a href="#url">Sort by Url </a>
                </td>
            </tr>
        </tbody>
    </table>
    <table cellspacing="0" cellpadding="0" border="0" width="100%" xmlns:crwp="urn:schemas-microsoft-com:CategoryResultsWebPart"
        xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:x="http://www.w3.org/2001/XMLSchema"
        class="ms-sitedirresultspaging">
        <tbody>
            <tr>
                <td> : </td>
            </tr>
        </tbody>
    </table>
    <table cellspacing="0" cellpadding="0" border="0" width="100%" xmlns:crwp="urn:schemas-microsoft-com:CategoryResultsWebPart"
        xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:x="http://www.w3.org/2001/XMLSchema"
        class="ms-sitedirresultsbody" id="table2">
        <tbody>
            <tr>
                <td valign="top">
                    <img alt="" src="/_layouts/images/lstbulet.gif" />
                </td>
                <td width="100%" class="ms-sitedirresultstitle">
                    <a href="http://site/cd10/_layouts/mysite.aspx?Redirect=1">Setup MySite</a>
                </td>
            </tr>
            <tr>
                <td />
                <td width="100%" class="ms-sitedirresultsurl">
                    <a dir="ltr" href="http://site/cd10/_layouts/mysite.aspx?Redirect=1">http://site/cd10/_layouts/mysite.aspx?Redirect=1</a>
                </td>
            </tr>
        </tbody>
    </table>
</div>

回答1:

<td>
    :
</td>

Doesn't contain : in either browser, as the trailing newline is different to a space. However:

<td> : </td>

now does give different results in IE and Firefox. The contains doesn't match in IE, because its parser has silently thrown away the whitespace, as IE likes to do. If you look at the innerHTML you see:

<TD>: </TD>

Which unsurprisingly doesn't match the selector.

So be careful with contains and whitespace because IE's HTML parser is as quirky as ever.

Personally I'd try to avoid non-standard jQuery selectors like :has and particularly :contains, as they require jQuery to do a lot of slow work. Standard CSS2-3 selectors, on the other hand, can be passed off to the browser's own selector engine in newer browsers with Selectors-API support (including IE8).

How about something like:

$('.ms-sitedirresultssort ~ table td').filter(function() {
    return this.text().match(/(^|\s):(\s|$)/);
})

~ is a CSS3 selector for any-following-sibling; IE8 does support it.



回答2:

Not sure if this is the case, but it seems possible that the issue may be to do with whitespace... for example if I try the html you provided & try to select with $("td:contains(' : ')") (in Firefox), I get no matches, because the content of the td you're trying to match is actually something like: <td>\n....:\n.....</td> (with . for spaces & \n for new lines). In other words it doesn't contain ' : ' because of the newline (selecting on ' :' works though). So its just a guess, but maybe IE8 does some clean up of the raw whitespace when creating its DOM tree, meaning that your ' : ' selector isn't matching properly.

So assuming there'll be other td's with :'s in them & you're just after the td with the single : (padded with random whitespace), you could use a slightly less specific selector & then filter that down functionally like this:

$("div[id^=WebPartWPQ]:has(table.ms-sitedirresultssort) td:contains(':')")
    .filter(function() { return $.trim($(this).text()) == ":"; })
    .closest('div');

Not quite as clean & probably a little slower, but might be a suitable work around.