『Javascript で HTMLエスケープを行うPHP関数、htmlspecialchars を実装』に一行追加

phpspot開発日誌さんJavascript で HTMLエスケープを行うPHP関数、htmlspecialchars を実装で紹介されているコードを使ってみたところ、不満な点が出てきたのでちょっぴり改良して使っています。

不満な点とは、既に「&」となっているコードを放り込むと、「&」と二重変換されてしまう点。改良後のコードは以下です。

function htmlspecialchars(ch) {
ch = ch.replace(/&/g,"&");
ch = ch.replace(/&/g,"&");
ch = ch.replace(/"/g,""");
ch = ch.replace(/'/g,"'");
ch = ch.replace(/</g,"&lt;");
ch = ch.replace(/>/g,"&gt;");
return ch;
}

追加したのは3行目。二重変換されちゃったものは元に戻すという、それだけです。

IEのDOMで特徴的だと思ったこと3点

最近、職場で勉強がてらJavaScriptでプログラムを書いています。会社の案件では少しjQueryを触ったりしたのですが、こちらではライブラリは極力使わない方針で。
そんな中、いくつか気づいたことを書き留めておきます。今回はIEの挙動で、特徴的だと思った点を3点。

responseXMLされたテキストノードをappendChildしようとするとエラーになる

Ajax通信したものをresponseXMLで受け取り、そこからテキストノードを抜き出して、createElementしたコンテナ要素にappendChildしようとすると、IEでは何故かエラーになりました。

回避方法:

// hogeが該当のテキストノード
var fuga = document.createTextNode(hoge.nodeValue)
container.appendChild(fuga)

周りくどいですが、テキストノードのnodeValue(テキストそのもの)を取り出して改めてcreateTextNodeします。これだけで解決。

table要素をcreateElementする際、子要素にtbodyを作らないとダメ

FirefoxとかOperaは、こっちがわざわざ作らなくても仮想的にtbodyを作ってDOMツリーを構成してくれます。だけどIEの場合はtbodyもこっちが作らないとダメ。作らなかった場合は不完全な要素ノードとなるため、appendChildとかしても何も表示されません。

そんな情報を検索している時に発見した、珍しいメソッドがtBodies[]

tBodies[]
table要素ノードのメソッド。tbody要素をノードリストで返す。
tableElement.tBodies[0]みたいにして使います。まぁ、tableElement.getElementsByTagName("tbody")[0]と書いても同じなわけですけど・・・。

参考:tBodies Collection (TABLE) – MSDN

要素ノードリストのアイテムにインデックス番号を振る際、 変数に格納した数値を入れるとエラーになることがある

解決方法:
とりあえずitem()メソッドで書けばOK

他のコードでも書いてみましたが、エラーが再現できず・・・どういう条件が重なると引き起こるのかよく分かりません。

appendChildに失敗する原因

最近はJavaScriptをいじってるのが楽しくなってきたのでそんなネタでも。

ノードをDOMツリーに追加するappendChildメソッド。当然ですが、ノード以外のものを追加しようとするとエラーになってしまいます。

例えば文字列を追加しようとした場合、Firebugのコンソールではuncaught exception:…とかいうエラーが出ます。数行に渡って激しく怒られるため、最初は一体何事かと思いました。

Firebugコンソールのエラー表示: uncaught exception...

例えば<p id="result">appendChild</p>というp要素があってそこにappendChildしたいとすると…

window.onload = function() {
var result = document.getElementById('result');
var string = '成功!!';
result.appendChild(string); // ←stringは文字列なのでエラー
}

文字列を追加したい場合はcreateTextNodeメソッドを使って文字列をテキストノードに変換する、もしくは最初からcreateTextNodeを使って文字列ではなくテキストノードを作ってappendChildしなければなりません。これで1時間は悩みました・・・orz

window.onload = function() {
var result = document.getElementById('result');
var string = '成功!!';
var textNode = document.createTextNode(string);// テキストノードに変換
result.appendChild(textNode); // ←textNodeはテキストノードなので成功
}

innerHTMLを使えば文字列のまま扱えますが、追加される対象親ノードの中身が全部書き換えられてしまう点に注意。innerHTMLだと"追加"というより"書き換え"っていう感じですね。

window.onload = function() {
var result = document.getElementById('result');
var string = '成功!!';
result.innerHTML = string;
}

Continue reading

アーカイブ一覧をJavaScriptで書き出すMTテンプレート

エントリーを新規投稿する度に、全てのページにあるアーカイブ一覧やタグクラウドをいちいち再構築させるのはだるい、と思い JavaScript で書き出すことにしました。SSI や PHP でやった方がスマートだと思いますが、サーバーサイドはいまいちよく分からないので・・・という軟弱な理由で今回は不採用。

MT テンプレートにして自動更新されるようにしたので、せっかくだからテンプレートを公開してみます。恥ずかしいくらいシンプルなシロモノですけれども。

アーカイブ一覧を書き出す JavaScript のテンプレート(txt形式)

「月別アーカイブ」・「カテゴリーアーカイブ」・「直近の10記事」・「タグクラウド」を書き出す命令を function に突っ込んでいるだけです。書き出す XHTML も各項目が li 要素でマークアップされているだけのシンプルなリストです。実際にこのサイトでテンプレートから構築された後の JavaScript はこうなっています(他のスクリプトも多少混在してますが)。

XHTML 側では下記のように関数を呼んであげればいいだけ。

<script type="text/javascript">
recentEntries();
categoryArchives();
tagCloud();
monthlyArchives();
</script>

ただし、当然 JavaScript が無効な環境ではなんにも表示されなくなりますのでご注意を。JS オフな環境を考慮して、トップページのみはこの方式のインクルードを採用せず、普通に XHTML で書いてます。また JS オフだとその旨を通知するメッセージが出るようにしました。いずれも 2xup さんのアイデアを参考にさせていただきました。でも 2xup さんのスクリプトの方が100倍はカッコいいので、間違っても比較しないように。。

またデメリットとして、動的に書き出すコンテンツは静的なコンテンツより一般的に SEO が弱いと言われている点ですね。だから内部リンクは弱くなるのではないかなぁとか思います。施策したばかりなので、Google ウェブマスターツールなどで見ても、まだその影響は現れていないようですが。