IT戦記

プログラミング、起業などについて書いているプログラマーのブログです😚

IE6 の JavaScript では href 属性の %20 と %25%32%30 の違いが分からない

これはひどい

/%20 と /%25%32%30 はリンク先が違うのに、 IE6 では判断する術がない。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<a id="id0" href="a%20a">foo</a>
<a id="id1" href="a%25%32%30a">foo</a>
<script>
var elm0 = document.getElementById('id0');
var elm1 = document.getElementById('id1');

alert(elm0.href == elm1.href); // true
alert(elm0.getAttribute('href') == elm1.getAttribute('href')); // true
alert(elm0.attributes.getNamedItem('href').nodeValue == elm1.attributes.getNamedItem('href').nodeValue); // true
alert(elm0.toString() == elm1.toString()); // true
</script>
</body>
</html>

IE8 に実装された getCascatedCSSSelectors 関数とは何か

4 月 1 日ですね!

getCascadedCSSSelectors 関数とは

getCascadedCSSSelectors 関数とは、 HTML54-1. the default views 定義されているインタフェースで、要素にあたっている CSS セレクタ配列で取得するための関数です。
window オブジェクト(グローバルオブジェクト)が持っている関数なので普通に、以下のように呼び出すことができます。

var element = document.getElementById('main-content');
var selectors = getCascadedCSSSelectors(element);

alert(selectors[0]); // #main-content
alert(selectors[1]); // div.section
alert(selectors[2]); // div
alert(selectors[3]); // *

たとえば、この例の場合は 4 つの計四つの CSS セレクタがあたっていることが分かります。

カスケード順とは何か

複数の CSS のルールが要素にあたっている場合に、優先される順のことをカスケード順と言います。

!important 宣言の扱い

一つのセレクタが示すルール内に !important 宣言を含むプロパティと !important 宣言を含まないプロパティが存在する場合、 getCascadedCSSSelectors の結果に同じセレクタが二つ含まれることになります。
たとえば、以下のような場合は

#hoge {
 font-size: 2em;
}
* {
 color: red;
 background: red !important;
}

結果は以下のようになります。

var element = document.getElementById('hoge');
var selectors = getCascadedCSSSelectors(element);

alert(selectors); // ['*', '#hoge', '*']

まとめ

getCascadedCSSSelectors 便利すぎる!
みなさんも触ってみてはいかがでしょうか。

IE6 と IE7 と IE8 を同じマシンで共存させる方法

追記:

現在は IETester というソフトウェアを使うのがベストだと思います><

結論から言うと

Jeremy Smith's blog: Success! IE 6, 7, and 8 Running on Same Machine (Plus 5.5 and 5.01) に書いてある通りで

  1. IE8 をインストール
  2. http://tredosoft.com/IE7_standaloneIE7 Standalone をインストール
  3. http://tredosoft.com/Multiple_IE の Multiple IE をインストール

の順で、共存させることができました。

IE8 を入れるのを戸惑っている人は

入れてみたらいかがでしょうか。

ちなみに

以下のサイトからダウンロードできる Standalone IE6 は IE8 と共存できませんでした。
browsers.evolt.org

VMware Fusion で同時起動したところ

左から IE6, IE7, IE8, Firefox 3.0b4, Safari 3.1, Opera 9.5b1

いい感じです。

JavaScript-XPath を IE8 に対応させました。

JavaScript-XPath をバージョンアップしました

久しぶりのバージョンアップです。よろしくお願いします><

JavaScript-XPath とは

JavaScript で書かれた XPath の実装です
以下からダウンロードできます。
http://coderepos.org/share/wiki/JavaScript-XPath

IE8 で実装された Selectors API とは何か?

はじめに

IE8 には Selectors API という新しい仕様が実装されました。
ということで、今後 DOM 操作 API の主流になるであろう Selectors API についてまとめておきます。

Selectors API が使えるブラウザ

2008 年 3 月 6 日現在の一覧

Selectors API とは

Selectors API とは W3C で定義された仕様です。詳細に関してはこちらをどうぞ
簡単に説明すると
getElementsByTagName や getElementsByName や getElementById などの DOMオブジェクトを取得するメソッドありますよね。
あれの「すごい版」の querySelector や querySelectorAll というメソッドのことを指します。
たとえば、既存の getElementsByTagName などのメソッドの代わりに Selectors API を使うと以下のようになります。

// 以下の二つは同じ要素を取得する
var nl00 = document.getElementsByTagName('div');
var nl01 = document.querySelectorAll('div');

alert(nl00[0] == nl01[0]); // true
alert(nl00[1] == nl01[1]); // true
  :
  :

// 以下の二つは同じ要素を取得する
var elm00 = document.getElementById('target');
var elm01 = document.querySelector('#target');

alert(elm00 == elm01); // true

// 以下の二つは同じ要素を取得する
var nl02 = document.getElementsByName('hoge');
var nl03 = document.querySelectorAll('*[name="hoge"]');

alert(nl02[0] == nl03[0]); // true
alert(nl02[1] == nl03[1]); // true
  :
  :

どうですか?簡単ですね?

querySelector や querySelectorAll には、 CSS セレクタを渡す。

前の例を見て気が付く方も多いと思いますが、 querySelector や querySelectorAll には CSS セレクタを渡します。
CSS セレクタとは、 CSS の中カッコの前に書かれる要素を特定するための文字列のことですね。
たとえば、以下の例で言うと

ul.navigation li {
  display: inline;
}

「ul.navigation li」が CSS セレクタにあたります。

(追記) 疑似クラスの扱い

id:vantguarde さんから以下のようなはてブコメントを頂きましたので、疑似クラスについて追記します。id:vantguarde さんありがとうございます!

擬似クラスなノードも取得できるってのを書いてほしいかも。

はてなブックマーク - vantguardeのブックマーク / 2008年3月6日

おっしゃるとおり Selectors API では疑似クラスにも対応しています。
たとえば、

// 現在選択されている要素を取得
var elm00 = document.querySelector(':focus');

// 現在マウスが乗っかってる要素を取得
var elm01 = document.querySelector(':hover'); // elementFromPoint と等価

このような感じになります。
ただ、プライバシーの配慮か単なるバグなのかは分かりませんが IE8 では :visited 疑似クラスは取得できませんでした。

alert(document.querySelectorAll('a:visited').length); // 常に 0
(追記) カンマで複数の CSS セレクタを指定できます。

カンマ自体が CSS セレクタの仕様の一部なので、当たり前と言えば当たり前ですが、これも書いておきます。

// 以下のように、カンマを使って複数の CSS セレクタを指定することもできます。
document.querySelectorAll('span, strong'); // span と strong 要素をすべて取得

querySelector と querySelectorAll の違い

querySelector と querySelectorAll の違いは、これも、最初の例で分かると思いますが、取得する要素が一個か複数かの違いです。
querySelector の場合は、そのセレクタが選択する要素の一番最初の要素だけを取得し、 querySelectorAll の場合はすべての要素を取得します。
例えば、以下のような HTML があったとします。

<html>
 ..(略)..
 <body>
  <ul><li>aaa</li><li>bbb</li><li>ccc</li></ul>
 </body>
</html>

そうすると、 querySelector は以下のようになります。

var elm = document.querySelector('body > ul > li');
alert(elm.innerHTML); // aaa

このように、 querySelector は HTML を上から順*1に見て一番最初に出て来た要素を選択します。
また、 querySelectorAll は以下のようになります。

var nl = document.querySelectorAll('body > ul > li');
alert(nl.length); // 3
alert(nl[0].innerHTML); // aaa
alert(nl[1].innerHTML); // bbb
alert(nl[2].innerHTML); // bbb

このように、 querySelectorAll も HTML を上から順*2に格納しています。
つまり、

document.querySelector(selector) // は
document.querySelectorAll(selector)[0] // と等価

ということです*3

querySelectorAll で取得される値

次は、 querySelectorAll で取得される値についてです。
この値は、配列のように扱えますが、配列ではありません。

// すべての要素を取得
var nl = document.querySelectorAll('*');

alert(nl instanceof Array); // false

// push などの配列のメソッドは使えない
try { nl.push('hoge') } catch (e) { alert('error') } // error

// 使えるのは length だけ
alert(nl.length);

ここまでは、従来の getElementsByTagName などで取得される値と同じです。
しかし、 querySelectorAll で取得される値の性質は getElementsByTagName などで取得される値とも少し違っています。

// すべての要素を取得
var nl00 = document.getElementsByTagName('*');
var nl01 = document.querySelector('*');

// ここで、 HTML の内容を書き換える(要素を一つ削除する)
document.body.removeChild(document.body.getElementsByTagName('*')[0]);

alert(nl00.length == nl01.length); // false

alert(nl00.length); // こちらは、変更が反映されて一つ少ない値になる
alert(nl01.length); // こちらは、変更が反映されない(取得時の状態)

このように、取得後に HTML の構造が変化した場合その変化を反映させるかさせないかの違いがあります。
また、それぞれのオブジェクトの名前を NodeList 、 StaticNodeList といいます。

NodeList getElementsByTagName などで取得される値 値取得後の HTML の構造の変化をその場で反映する
StaticNodeList querySelector で取得される値 取得時の状態のままで、変化が反映されない

一見、 getElementsByTagName の仕様のほうが便利に思えますが、この動的な性質があったせいで処理が重くなっていたんですね。
だから、 querySelectorAll は取得した値の操作が軽いかもしれませんね。

document だけじゃなく、要素からも使えます。

今までは、 document.querySelectorAll とやってきましたが、普通に要素でも使えます。
要素で、実行した場合は子孫要素から要素が選択されるようになります。

var elm = document.querySelector('#target');

// elm の子孫要素で hoge というクラスを持つ要素
elm.querySelectorAll('.hoge');  // つまり、 #target .hoge と同じ

まとめ

こんな感じです!超便利ですね!
DOM 3 XPath 派な僕ですが。やっぱり IE8 が Selectors API を実装したので、これから Selectors API の時代が来ると思います。
他のブラウザも早く実装して欲しいですね!
この便利なメソッドが使えるようになるのは非常に楽しみです><
ではでは!
(Namespace については省略しました。)

*1:このような順番のことをドキュメント順と言う

*2:このような順番のことをドキュメント順と言う

*3:もちろん、結果が等価ということであって、実行効率とかは違うかもしれません。

インターネットが出来なくなりました (ノ_≦。)

今日パソコンをたちあげたら、インターネットが立ち上がらなくなりました (ノ_≦。)

パソコンに詳しい友人に聞いてみると、「IE7 という新種のウィルス」ではないかとのことでした。
どうしたらいいでしょうか。助けてください。

いろいろと明日を先取りしてみた。
IE7 に対応していないツールバー拡張などを入れていると
IE7 が不具合を起こす可能性もあるらしいので、ご注意を。