jQuery(Sizzle)のIE6, 7における:textのバグと対策

IE6, 7で iframeを含むページで:textを走らせるとエラー

なんぞこれー、と思って検証してたらissueでてた。察しが付いてきた時点で、先に見ればよかった。||| orz

検証コード

以下のコードをレガシーIEで実行すると、:textだけエラーが出てundefinedを返しfailedになります。iframe要素まではいいけど、src属性がクロスドメインな時点でアウト。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xml:lang="ja" lang="ja" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
    var results = document.getElementById('results'),
        exprCollection = [
            ':text', ':input', ':password', ':radio', 'checkbox',
            ':submit',':image', ':reset', ':button', ':file'
        ],
        i = 0,
        expr;

    function test(expr) {
        if ($(expr) === void 0) {
            throw Error(expr);
        }
    }

    function succeed(expr) {
        results.innerHTML += '<dt>'+expr+'</dt><dd>succeed</dd>';
    }

    function failed(expr) {
        results.innerHTML += '<dt>'+expr+'</dt><dd>failed</dd>';
    }

    while(expr = exprCollection[i++]) {
        try {
            test(expr);
        } catch(e) {
            failed(expr);
            continue;
        }
        succeed(expr);
    }
});
</script>
</head>
<body>
<h1>(´Д`)</h1>
<dl id="results">

</dl>
<iframe width="640" height="360" src="http://www.youtube.com/embed/HiRgU78_g9o" frameborder="0" allowfullscreen></iframe>
</body>
</html>

Sizzleさん

SizzleというjQueryが内包しているセレクタエンジン(querySelectorの代替品+α)のバグですね。jQueryのセレクタAPI周りは2つめのURLの情報がよろしいです。

バグじゃ〜ん

内容的には、iframeでクロスドメインを引き込んでいると、getAttribute("type")をレガシーIE的に使えないのが理由らしい。判明してから半年以上経ってるし、プライオリティが低いからとりあえずこの場を凌ぐ。

対策

jQuery.expr.filters.textをスクリプトの冒頭で上書きします。さきほどのGitHubのページに対策コードも掲載されていたので、とりあえずそれを丸々拝借します。

// @see https://github.com/jquery/sizzle/issues/66
jQuery.expr.filters.text = function( elem ) {
    var attr, type;
    return elem.nodeName.toLowerCase() === "input" && (type = elem.type, attr = elem.getAttribute("type"), "text" === type) && ( attr === type || attr === null );
};

これで対策できました。副作用があるようだったら、この中身を改造していけばよいかな〜、と思いながらこれでやり過ごします。assigned bugってことは、そのうち直るのよ...ね?

参考