jQuery(Sizzle)のIE6, 7における:textのバグと対策
Posted: Updated:
IE6, 7で iframeを含むページで:textを走らせるとエラー
あ、これか Issue #66: :text selector throws an error in IE7 when there is a cross domain iframe on the page · jquery/sizzle github.com/jquery/sizzle/…
— あほむ@世界樹の迷宮たのしみ (@ahomu) March 16, 2012
なんぞこれー、と思って検証してたら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 JavaScript Selector Library
- jQueryのCSSセレクタAPIを高速に扱う方法 | tech.kayac.com - KAYAC engineers' blog
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ってことは、そのうち直るのよ...ね?
参考
- Issue #66: :text selector throws an error in IE7 when there is a cross domain iframe on the page · jquery/sizzle
- #10570 (:text selector throws an error in IE7 when there is a cross domain iframe on the page) – jQuery Core - Bug Tracker