スポンサーリンク
カテゴリー:"JavaScript"

JavaScriptのremoveChildを使う際の注意点

JavaScript の removeChild を使ってノードの削除をしようとしてハマったので。

そもそもは、とあるノードの子ノードを全て削除する関数を書いてたのですが、これがどうにもうまく行かなくて、新JavaScript例文辞典子ノードを全て削除する (removeChild) にあった関数を使ったら、上手く動いたんです。

というわけで、それを参考に書き直したのが以下の関数です。引数はHTML要素のIDで、該当要素の子要素を全て削除します。

function delInnerHtmlAll(nodeId) {
  var element = document.getElementById(nodeId)
  for (var i=element.childNodes.length-1; i>=0; i--) {
    element.removeChild(element.childNodes[i]);
  }
}
 

で、「何で上手く行かなかったんだろう?」 といろいろ試してみた結果、for ループの回し方がダメだったんですね。

当初、僕は

for (var i=0; i<element.childNodes.length; i++) {
 
と書いてたんですが、頭から消していってはいけなかったんです。

想像するに、最初の要素を削除した場合、Perl で配列に対して shift を実行したときように、添字に対する要素がズレていくのが原因ではないかと思われます。

具体的には、1番目の要素が削除されると2番目の要素が1番目の要素として再設定されて、3番目以降の要素についても同様にズレていって、最終的には配列としての長さが1短くなるというイメージかな。

なるほど、それでは上手く動かないわけだ。

参照リンク
 ・子ノードを全て削除する (removeChild) by 新JavaScript例文辞典

JavaScriptを使ってセキュアなログインを実現する MD5(Digest)認証

Webアプリで、SSL を使わなくてもセキュアなログインは実現できないものか? と調べていたら、Digest認証(MD5認証)なる方法を見付けたのでメモメモφ(..)。

前提条件としては、ユーザーのIDとパスワードのハッシュ文字列(MD5でハッシュしたもの)を、予めサーバー側に保存しておきます。

実際のデータのやりとりは、以下のとおりになります。

1.クライアント
ⅰ.サーバーに対し、ログインページをリクエスト
2.サーバー
ⅰ.クライアントにランダムな文字列(nonce)を埋め込んだログインページを返す
3.クライアント
ⅰ.ユーザーが入力したパスワードからハッシュ文字列(cMd5pw)を作成
ⅱ.ユーザーが入力したID(id)と、 cMd5pw, nonce からハッシュ文字列(response)を作成
 response = MD5(cMd5pw + nonce + id)
ⅲ.id, nonce, response をサーバーに送信
4.サーバー
ⅰ.クライアントから送られてきた id, nonce と、サーバーに予め格納されているパスワードのハッシュ文字列(md5pw)から、新たにハッシュ文字列(reResponse)を作成
 reResponse = MD5(md5pw + nonce + id)
ⅱ.クライアントから送られてきた response とサーバー側で作成した reResponse を比較して、一致すれば認証成功!

この方法なら平分のパスワードはおろか、ハッシュ化されたパスワードのやりとりもありませんし、サーバーに平文のパスワードを保存しておく必要もないので、パスワードの保護という点においてはかなり強そうです。

参照リンク
 ・Digest認証 - Wikipedia
 ・HTTP クライアントを作ってみよう(6) - Digest 認証編 -

MD5を計算するJavaScriptライブラリ
 ・md5.js (mitsunari@cybozu labs)

関連エントリー
 ・JavaScriptでMD5を計算するライブラリ 「md5.js」

JavaScriptでMD5を計算するライブラリ 「md5.js」

JavaScript で MD5 を計算するライブラリを探してみました。探す前から 「誰かは作ってるだろうなぁ」 とは思ってたんですが、思いの外あるもんですねぇ。

その中から今回は、mitsunari@cybozu labs で公開されている md5.js を試してみました。理由は、開発者さんが 「同種のライブラリに比べて3~7倍ほど高速」 と言っておられたので。

テストに使ったサンプルコードは以下のとおり

<html>
<head>
  <META http-equiv="content-type" content="text/html; charset=UTF-8">
  <script type="text/javascript" src="./md5.js"></script>
  <script type="text/javascript">
  function ToMD5(){
    var seed = document.getElementById('input1').value;
    document.getElementById('input3').value = CybozuLabs.MD5.calc(seed);
  }
  </script>
</head>
<body>

<input type="text" id="input1" style="width:35em;"><br>
<input type="button" value="Click!" onClick="ToMD5()"><br>
<br>
結果:<input type="text" id="input3" style="width:35em;">

</body>
</html>

うん、いい感じ。

参照リンク
 ・md5.js (mitsunari@cybozu labs)

JavaScriptからCSSのプロパティ値を読み出そう

JavaScript から HTMLエレメントに指定されている CSSプロパティの値(属性値)を取得する場合、

とするのが一般的みたいなんですが、このやり方ではインラインで設定された属性の値しか読み込めないんですよね。

ところが、getComputedStyle という関数(?)を使うと、インラインで設定した以外の属性の値も引っ張って来れると知りまして、ついでなので使いやすいように関数にしてみました。

使い方のサンプルは以下の通りです。

動作確認は、Windows XP SP3 上の IE8、Firefox 7.0.1、Opera 11.51、safari 5.0.5、Chrome 14.0.835 で行いました。

Enjoy!

参照リンク
 ・JavascriptでCSSのプロパティ値を取得する方法 ≪ 来栖川電算
 ・getComputedStyle について調べてたら深みにハマったのでメモ - IT戦記

JavaScriptで縦書きにレイアウトするライブラリ 「tategumi.js」

MOONGIFT さんで紹介されていた、Webページを縦書きにしてくれるテキストレイアウトエンジン tategumi.js を使ってみました。

1行の文字数と1ページの行数の指定が可能なので、実際の本にあるような読みやすいレイアウトが簡単に再現できるのはありがたいですね。もちろん文字サイズ、字間、行間も指定可能になっています。

また、文章の種類(?)として、タイトル、本文、キャプションの指定が別々にできるので、タイトルだけ大きくしたい場合とかに便利そうです。

ただし HTMLらしい装飾には対応していない(というか、装飾すると縦書きにならない)ようなので、ベタなテキストを縦書きするため。と割り切って使っうのが良さそうです。

段落の先頭を一字下げにしたい場合も、段落の先頭に全角スペースを置く事でうまくいきましたし。

マークアップについても非常にシンプルなので、HTMLに詳しくない人でもソースをコピーして、チョチョッといじれば何とかなるんじゃないかなぁ?

テストに使ったソースは、以下のとおり。

結果はこんな感じになりました。

なお禁則処理もできるということなので、ライブラリのソースをざっくり読んでみたんですが、現時点では “追い出し” のみが可能なようでした。

参照リンク
 ・Kumihan Project - Alliance Port, LLC
 ・allianceport/tategumi.js - GitHub
 ・日本の文章はやはり縦書きが読みやすい「tategumi.js」 - MOONGIFT|オープンソース・ソフトウェア紹介を軸としたITエンジニア、Webデザイナー向けブログ

JavaScriptで文字列を数値に変換しよう

JavaScript から <input type="text"> タグの値を取り出すと、問答無用で文字列として扱っちゃうんですよね。

ですから数値を入力させてから数値演算をしようとした場合には、取り出した値を文字列から数値へ変換しなくちゃいけません。

ちょっと調べてみたところでは、JavaScript には値を文字列から数値へ変換する関数が、用途に合わせて3つが用意されているようです。

  • num = Number( str )
  • num = parseInt( str , int )
  • num = parseFloat( str )

ところがですねぇ、parseInt() はブラウザによって挙動が異なる場合があるらしいんですよ。そんなわけで、とりあえず parseInt() は使わないことにします。

さて、残った Number() と parseFloat() の違いですが、僕が確認した限りでは以下の通りでした。

  Number('1.5')          /* 結果: 1.5      */
  parseFloat('1.5')      /* 結果: 1.5      */
  
  Number('05')           /* 結果: 5        */
  parseFloat('05')       /* 結果: 5        */
  
  Number('2.4e3')        /* 結果: 2400     */
  parseFloat('2.4e3')    /* 結果: 2400     */
  
  Number('2.4e-3')       /* 結果: 0.0024   */
  parseFloat('2.4e-3')   /* 結果: 0.0024   */
  
  Number('1.5a')         /* 結果: NaN      */
  parseFloat('1.5a')     /* 結果: 1.5      */
  
  Number('a1')           /* 結果: NaN      */
  parseFloat('a1')       /* 結果: NaN      */

個人的には、最後の parseFloat('a1') が 0 を返してくれると、非常に便利だったんですけどねぇ。残念。

でもまぁ、NaN が返ってきたら 0 に置き換えるロジックでも組み込んでおけば、問題ないかな。

なお、動作確認は Firefox 4.0.1 と IE8 で行いました。

setTimeout関数を使ってJavaScriptの処理を非同期化してみる

わかったブログ さんの「遅いブログパーツを高速表示する方法」で紹介されていた setTimeout関数を使った JavaScript の処理の非同期化がなかなか使えたのでメモメモです。

一般にHTMLファイル内に下記のようなコードがあった場合

<script type="text/javascript">
  example();
</script>

ブラウザは example() の処理が終わるまで次の処理に進まないんですよね。このソースがHTMLファイルの中ほどにあって、なおかつ example() の処理に非常に時間がかかる場合、ユーザーにはWebページの表示(描画?)が止まっているように見えるわけです。

そこでソースを

<script type="text/javascript">
  setTimeout(function() {example();}, 0);
</script>

のように変更すると、ブラウザは example() の処理を実行しつつも、example() の終了を待たずに次の処理に進むので、ユーザーにはWebページの表示が高速化して見える。というわけです。

実際にこのブログで試してみたんですが、確かに処理が非同期化されてました(ブラウザは Firefox 3.6.13 で確認しました)。

この手を使えば JSONP を使った別ドメインとの通信(及び処理)なんかも非同期化できそうですし、他にもいろいろと応用が利きそうです。

つか、setTimeout で処理の非同期化ができるとは、知りませんでした。

参照リンク
 ・遅いブログパーツを高速表示する方法 - わかったブログ
 ・setTimeout/JavaScriptリファレンス
 ・一定時間後に処理を行う(setTimeout) - ウィンドウ(window) - JavaScript入門

JavaScriptで現在日時を取得する関数を書いてみました

JavaScriptからクライアントマシンの現在日時を取得する関数を書いてみました。

はじめは Dateオブジェクトの getYearメソッドを使ってたんですが、案の定というか、IEだけ振る舞いが違うじゃないですか~!

仕方がないので getYearメソッドの戻り値が 2000より小さかったら 1900を足すようにしてたんですが、隣の席から 「getFullYearメソッドでいいんじゃないっすか?」との声が。

Webで調べたら、「古いブラウザの Dateオブジェクトには getFullYearメソッドが無い」という情報もありましたが、テストしたところ IE5.0 では問題なく動きました。

ま、IE5.0より古いブラウザは無視してもいいよね。というわけで、 getFullYearメソッドを採用した結果が以下のソースです。

function Now(){
  var DT  = new Date();
  var now = new Object();
  
  now.year  = DT.getFullYear();
  now.month = DT.getMonth() + 1;
  now.day   = DT.getDate();
  now.hour  = DT.getHours();
  now.min   = DT.getMinutes();
  now.sec   = DT.getSeconds();
  
  return(now);
}

呼び出すときはこんな感じで。

function ShowDateTime(){
  var now = Now();
  
  alert(now.year +'/'+ now.month +'/'+ now.day +' '+ now.hour +':'+ now.min +':'+ now.sec);
}

参照リンク
 ・時間を取得する JavaScript
 ・日付(Date)|JavaScriptリファレンス|とほほのWWW入門

JavaScriptを使ったブログパーツを作る時の注意点

小飼弾氏より、blogパーツ開発者に向けて要望(というかツッコミ?)が入りました。曰く

  1. 名前空間を一つだけ用意して、それのみを使うこと
  2. 設定はグローバル変数ではなく、引数渡しにすること

そうでないと、導入したサイトで変数衝突が起こる公算が大きくなります。

404 Blog Not Found:javascript - ブログパーツ/ウィジェット開発者におねがい より引用

あぅあぅ。仰られていることは至極もっともであり、とりあえず自分の開発したblogパーツがどうなっているか確認してきました。

結果としては、概ね小飼弾氏が指摘されている内容を実装できていて、ちょっと安心。

具体的には、名前が衝突しそうにないグローバルオブジェクトを1つ作って、値はそのオブジェクトのプロパティに設定する。というやり方をしておりました。

サンプルソースは以下な感じになります。実際にはパラメータを引数で渡すのではなく、直接オブジェクトのプロパティに設定するようにしてたので、小飼弾氏のサンプルソースを参考に書き直すとこんな感じかなぁ?。

読み込まれるファイル(blogparts.js)のソースの例:

if ( typeof(jp_oreore_blogparts) == 'undefined' ) jp_oreore_blogparts = new Object;

jp_oreore_blogparts.show = function(x){
   jp_oreore_blogparts.id    = x.id;
   jp_oreore_blogparts.url   = x.url;
   jp_oreore_blogparts.style = x.style;
   
   alert(jp_oreore_blogparts.id+" : "+jp_oreore_blogparts.url+" : "+jp_oreore_blogparts.style);
}

blogに追加するソース(snippet)の例:

<script type="text/javascript" src="http://oreore.jp/js/blogparts.js"></script>
<script type="text/javascript">
<!--
jp_oreore_blogparts.show({id:22,url:"http://blog.mukairiku.net/",style:"b"});
// -->
</script>

もちろん本番のコードでは、使用するオブジェクトやプロパティが未使用かどうかのチェックとか、使用されている場合はどう対応するのか?という部分まで考慮せにゃなりませんけどね。

参照リンク
 ・404 Blog Not Found:javascript - ブログパーツ/ウィジェット開発者におねがい

JavaScriptの手の届かないところを調べてみました

今更感満載ですが、JavaScriptって異なるサーバーから読み込んだドキュメントのプロパティにはアクセスできなかったんですねえ。

具体的には別サーバーに置いてあるHTMLファイルをiframe内に表示させた際に、読み込んだHTMLファイルに合わせてiframeの高さを自動で調節したかったんですが・・・。そこにはアクセス出来ないよ。と怒られちゃいました。

というわけで、JavaScriptから何処にアクセスできないのかを調べてみました(何か抜けてたらごめんなさい)。

  1. 異なるサーバーから読み込んだドキュメントやウィンドウのプロパティ
  2. 異なるサーバーから読み込んだドキュメントやウィンドウのイベント
  3. <input type="file">要素への値の設定
  4. プラウザの履歴の内容(Historyオブジェクト内の具体的なURL)
  5. ブラウザのキャッシュの内容
  6. ブラウザの設定の内容

確かにどれも勝手に触られたら嫌だなぁ。

他にも、スクリプトが作成したのではないウィンドウを閉じようとしたり、mailto:またはnews:形式のフォームを送信しようとすると確認ダイアログが出るんだとか。

常識としてローカル(PC)のリソースへはcookie以外はアクセスできない。てのは知ってたんですが、勉強になりました。

スポンサーリンク

プロフィール


  • 書いてる人:夢界 陸

    名古屋在住のおっさん。
    プログラミングやガジェットの話など、 日々の興味を徒然と綴っています。



    Twitterやってます @mukairiku



    運営サイト
    www.mukairiku.net

ブログ内検索

Licenses

  • Creative Commons License

OTHER

  • このブログのはてなブックマーク数

Blog powered by TypePad

スポンサーリンク