トップページ | 2006年7月 »

2006年6月30日 (金)

FireBugのインストールと簡単な使い方

昨日、FireBugが@ITで紹介されていたせいか、"FireBug"という検索キーワードでGoogleなどからこのブログにやってこられる方が急に増えました。
以前、紹介程度には書いていたんですが、わざわざ見に来てもらってそれだけでは申し訳ないので、導入から簡単な使い方までを書いておきます。

◆インストール
インストールはいたって簡単です。
Firefox 1.5以上でこちらのサイトにアクセスします。
そのページの真ん中より少し上に以下のような部分がありますので、「Install Now」をクリックます。


すると、以下のようなダイアログが出るので、「今すぐインストール」を押してインストールを行います。


ダウンロードが完了すると以下のダイアログが出ますので、FireBugの項目があることを確認してFirefoxを再起動して完了です。



◆簡単な使い方
Firefoxを起動すると、ステータスバーの右端に、ページにエラーがなければ の アイコンが、エラーがあると のような アイコンが表示されます。
そのアイコンをクリックすると、以下のようにデバッグ用のペインが開きますので真ん中の「Debugger」タブを開くと、そのページ内のJavaScriptのソースが表示されます。


外部ファイルなど複数存在する場合は、下にある「Scripts」というドロップダウンでファイルを選択してください。
ここで、左側の行数が書かれている部分をクリックすると、ブレイクポイントを設定できます。
デバッグしたい行にブレイクポイントを設定してJavaScriptを実行すると、以下のようにブレイクポイントでプログラムが中断します。黄色の行がこれから実行されるプログラムです。


この時、右側のペインではその時点での変数の値を確認することが出来ます。
ここで左下にある水色の再生ボタンを押すとプログラムが再度実行され、次のブレイクポイントがあればそこで再度中断となります。
また、ここから1行ずつプログラムを実行していくには、3つの黄色い矢印ボタンを使用します。
一番左はステップオーバーで、次の行へ進みます。
真ん中はステップインで、現在の行が関数の呼び出し部であればその関数内に入ります。
一番右はステップアウトで、現在の関数を抜けて外に出ます。

軽量でお手軽にデバッグ出来ますので、おすすめです。


IEでデバッグしたいという場合は、Visual Studio 2003とか2005をお使いの方は、それでデバッグ出来ます。
お持ちでない方は、Visual Web Developer 2005 Express EditionというVisual Stuio 2005のASP.NET開発に機能を限定したものが無料で入手出来ますので、こちらを使ってデバッグ出来ます。
軽量ではありませんし、プロジェクトの作成などが必要でお手軽というわけでもありませんが、機能は非常に充実していますので、ASP.NETとは無縁の方も一度お試し下さい。

| | コメント (0) | トラックバック (1)

2006年6月29日 (木)

prototype.js その他の便利機能

prototype.js にはAjax以外にも便利な機能があります。
その中からDOMの要素に関する機能をいくつか紹介しようと思います。

$() 関数
この関数は、DHTMLで頻繁に出てくる document.getElementById() のショートカットとして使用できます。
使用例:
var element = $("ElementId");
element.innerHTML = "....";

また、この関数には複数のIDを指定することも出来ます。
その場合は、指定した要素が配列で返ってきます。
使用例:
var elements = $("ID1", "ID2", "ID3");
for(var i=0;i<elements.length;i++){
    elements[i].style.display = "none";
}

Elementクラス
このクラスは、DOMの要素を操作する際に便利です。
以下のようなメソッドが用意されています。
getDimensions メソッド
要素のサイズを取得することが出来ます。
引数には要素のIDまたはインスタンスで、 戻り値は、widthとheightというプロパティを持つオブジェクトです。
使用例:
var d = Element.getDimensions("ElementId");
alert("width=" + d.width + ",height=" + d.height);

getStyle メソッド
要素のスタイルを取得できます。
引数は要素のIDまたはインスタンスと取得したいスタイル名で、戻り値はCSSスタイルの値です。
使用例:
alert(Element.getStyle("ElementId", "border"));

setStyle メソッド
要素のスタイルを設定できます。
引数は要素のIDまたはインスタンスと設定したいスタイル名と値のペアです。
使用例:
var styles = {"color":"red", "background-color":"blue"};
Element.setStyle("ElementId", styles);

hide メソッド
CSSスタイルのdisplayをnoneに設定して、要素を非表示にします。
引数は要素のIDまたはインスタンスです。複数指定することが出来ます。
使用例:
Element.hide("ElementId1", "ElementId2");

show メソッド
hideメソッドとは逆に、要素を表示します。
引数は要素のIDまたはインスタンスです。複数指定することが出来ます。
使用例:
Element.show("ElementId1", "ElementId2");

toggle メソッド
要素の表示状態を反転します。表示状態であれば非表示に、非表示状態であれば表示状態になります。
引数は要素のIDまたはインスタンスです。複数指定することが出来ます。
使用例:
Element.toggle("ElementId1", "ElementId2");

remove メソッド
要素を削除します。hideメソッドと見た目は同じような動きですが、元に戻すことは出来ません。
引数は要素のIDまたはインスタンスです。
使用例:
Element.remove("ElementId");

Elementクラスには他にもメソッドがありますので、機会があればご紹介したいと思います。
prorotype.jsには、他にもまだまだ便利な機能がありますので、明日も引き続きご紹介したいと思います。

| | コメント (0) | トラックバック (0)

2006年6月28日 (水)

prototype.js で Ajax

prototype.jsはJavaScriptのライブラリで、色々と便利な機能を提供していますが、 やはり、このライブラリのAjaxの機能が目当てという方が多いんじゃないでしょうか。
実際、XMLHttpRequest関係のブラウザ毎の差異を吸収してくれて、とても簡単に利用できます。

以下のコードはサーバーからデータを受信するものですが、たったこれだけでOKです。
function showData(res)
{
    alert(res.responseText);
}

function getData()
{
    var url = "test.txt";
    var options = {method:"GET", onComplete:showData};
    new Ajax.Request(url, options);
}


アクセスできるURLは、セキュリティの制限により同一のドメインのみに限られています。
optionsの指定は、JSONフォーマットとか言われたりしますが、キーと値のペアをカンマで区切って指定します。
他に指定できるoptionとしては、リクエストする際に渡すパラメータを指定するparametersや、通信の同期・非同期を指定するasynchronousなどがあります。
asynchronousのデフォルト値はtrueになっており、何も指定しなければ非同期通信となります。
onCompleteでは、通信が完了した際に呼ばれる関数を指定しています。
この関数には引数としてXMLHttpRequestオブジェクトが渡されますので、例のようにresponseTextで値を取り出します。
new Ajax.Request(url, options)の部分は、私は最初は少し違和感を感じましたが、この1行でリクエストを送信します。

この他、HTMLの要素の中身のみを更新する目的で利用するAjax.Updaterというクラスもあります。
function updateData()
{
    var url = "test.html";
    var options = {method:"GET"};
    new Ajax.Updater("ElementId", url, options);
}


ほとんどAjax.Requestの時と同じです。
Ajax.Updaterの最初の引数には、中身を更新する要素のIDまたはインスタンスそのものを指定します。
test.htmlには、
<span style="color:red;"><b>Hello Ajax!</b></span>
と書いてあり、通信が完了すると自動的に受け取った値を要素に挿入するといった動作になります。
したがって、サーバーが返す値はHTMLタグである必要があります。
上の実行例ではbuttonタグのIDを指定していますので、実行するとボタンのキャプションが変わります。

| | コメント (0) | トラックバック (0)

2006年6月26日 (月)

ココログ記事検索の仕組み Part 3

さて、最後は検索と検索結果の表示です。
検索は昨日載せたBlogEntryクラスのsearchメソッドで行っているのですが、特に変わったことはしておらず、単に正規表現で マッチしたらヒットした部分付近の文字列を返しているだけです。
そして、その結果表示は以下のような感じで行っています。
var root = document.createElement('div');
				
var te = document.createElement('a');
te.appendChild(document.createTextNode(entry.title));
te.href = 'javascript:showEntry("'+entry.url+'");';
root.appendChild(te);

var ce = document.createElement('div');
ce.innerHTML = hitString;
root.appendChild(ce);

$("result_element").appendChild(root);
エレメントをいくつか生成していますが、これは以下のような構造のHTMLを構築しています。
<div>
<a href="javascript:showEntry(URL);">タイトル</a>
<div>ヒットした部分文字列</div>
</div>
$("result_element") の部分は見慣れないかもしれませんが、これはPrototype.jsで定義されている関数で、 DynamicHTMLで頻繁に登場する document.getElementById の代わりに使用することが出来ます。
これによって、コードが若干短く、見やすくなると思います。
つまり、この場合は
document.getElementById("result_element").appendChild(root);
と同じことを行っています。
result_elementというのは、あらかじめ結果表示用に用意してある緑色の枠のレイヤーです。

これで、検索結果を表示用に用意してあるレイヤーに挿入できましたので、後はレイヤーを表示して完了です。
ここまで見ていただけるとわかるように、コードの大半は記事の抽出のためのものですので、記事が増えると遅くなってしまうと思いますが、 少しずつ改良していく予定です。

| | コメント (2) | トラックバック (0)

2006年6月25日 (日)

ココログ記事検索の仕組み Part 2

昨日は、月別にアーカイブされた記事のURLを取得するところまで書きましたので、今日はそのURLからHTMLを取得して検索を行う部分を書きます。
まず、以下のように月別のURLを格納している配列から順にHTMLを取得しています。
for(var i=0;i<cocosearch_archiveUrls.length;i++){
    var url = archiveUrls[i];
    new Ajax.Request(url, {method:'GET',onComplete:entryPageLoaded});
}
そして、HTMLが読み込まれるときに呼ばれるように指定しているentryPageLoaded内で検索を行っています。
そのentryPageLoaded関数は、以下のような感じです。
var BlogEntry = Class.create();
BlogEntry.prototype = {
    initialize : function(title, content, date, url){
        this.title = title;
        this.content = content;
        this.date = date;
        this.url = url;
    },

    search : function(keyword){
        var re = new RegExp('('+keyword+')', 'ig');
        var r;
        if((r=re.exec(this.content))){
            var i = r.index;
            i = (i > 25) ? (i-20) : i;
            var l = (this.content.length-i	> 100) ? 90 : this.content.length-i;
            return "..." + this.content.substr(i, l).replace(re, '<b>\$1</b>') + "...";
        }
        return "";
    }
};

var entryCache = [];

function entryPageLoaded(r)
{
    var text = r.responseText.replace(/[\r\n]/g, "");
    var pt1 = '<div class="entry-top">.*?<div class="entry-bottom"></div>.*';
    var re1 = new RegExp(pt1, "gi");
    var pt2 = '<div class="entry">.*<h3>(.*?)</h3>';
    pt2 += '.*<div class="entry-body-text">(.*?)<div class="entry-body-bottom"></div>.*';
    pt2 += '<span class="post-footers">(.*?)<a href.*<a class="permalink" href="(.*?)">';
    var re2 = new RegExp(pt2, "gi");
    var results = text.match(re1);
    
    for(var i=0;i<results.length;i++){
        results[i].match(re2);
        var title = RegExp.$1;
        var content = RegExp.$2;
        var date = RegExp.$3;
        var url = RegExp.$4;
        content = content.replace(/<.*?>/gi, "");
        var blogEntry = new BlogEntry(title, content, date, url);
        entryCache.push(blogEntry);
        searchEntry(blogEntry);
    }
}
まず最初のBlogEntry = Class.create();の部分ですが、これはPrototype.jsの機能で、このように書くとクラスを定義することが出来ます。
このBlogEntryというクラスでは、記事のタイトル・内容・日付・URLを持つプロパティと、searchという検索を行うメソッドを定義しています。
切り出した各々の記事からこのBlogEntryクラスを生成し、その後に定義してあるentryCacheという配列に格納することで2回目以降の検索を高速化することが目的です。

月別にアーカイブされたページのHTMLの構成は、
<div class="entry-top">
....<div class="entry">.....<h3>1つ目の記事のタイトル</h3>....
....<div class="entry-body-text">1つ目の記事の内容<div class="entry-body-bottom"></div>
....<span class="post-footers">1つ目の記事の日付<a href="...">.....<a class="permalink" href="1つ目の記事のURL">....
...........
....<div class="entry">.....<h3>2つ目の記事のタイトル</h3>....
....<div class="entry-body-text">2つ目の記事の内容<div class="entry-body-bottom"></div>
....<span class="post-footers">2つ目の記事の日付<a href="...">.....<a class="permalink" href="2つ目の記事のURL">....
<div class="entry-bottom"></div>
のようになってます。
このような構成のHTMLから記事だけを抽出するために、entryPageLoaded関数では、まず<div class="entry-top">から<div class="entry-bottom"></div>までを切り出し、その結果から記事のタイトルや内容を抽出する作業をforループ内で繰り返し行っています。
記事の内容に関しては、HTMLタグが含まれていますのでタグが検索にヒットしないように、
content = content.replace(/<.*?>/gi, "");
の部分でHTMLタグを除去しています。

長い道のりでしたが、これでやっと記事の抽出まで完了しました。
この後は検索を行い結果を表示する部分ですが、長くなってしまいましたので続きはまた明日書きたいと思います。

| | コメント (0) | トラックバック (0)

2006年6月24日 (土)

ココログ記事検索の仕組み

コメントをいただいたので、先日設置した記事検索の仕組みについて書きたいと思います。
まず、ブログの場合、サーバーサイドのプログラムでデータベースなどにアクセスできないので、 ブログシステムが生成するHTMLファイルをJavaScriptを使って力技で強引に検索するしかありません。
つまり、最初に、記事が書かれているHTMLファイルのURLをどうにかして取り出す必要があるわけです。
色々見てみると、ココログの場合はブログのルートディレクトリにあるarchives.htmlというファイルからそのURLをたどれそうです。
左のサイドバーにある「バックナンバー」というリンクがそのファイルを指していて、 そのファイルを開くと月別に記事をまとめたHTMLファイルへのURLが書かれています。
具体的には以下のような形式になっています。
<div id="archive-datebased">
.......
<a href="http://wildcat.cocolog-nifty.com/web/2006/06/index.html">2006年6月</a>
.......
<div class="archive-category">
.......
つまり、<div id="archive-datebased">から<div class="archive-category">の間にあるaタグのhref属性を取り出せばOKということですよね。
そこで、まずXMLHttpRequestを使ってarchives.htmlのHTML文字列を取り出します。
今回は楽をするためにPrototype.jsを利用していますので、コードは以下のようなものになります。
var BLOG_URL = "http://wildcat.cocolog-nifty.com/web/";
........
var url = BLOG_URL + "archives.html";
new Ajax.Request(url, {method:'GET',onComplete:archivePageLoaded});
Prototype.jsについてはあらためて書こうと思っていますが、ご存知ない方は、1つ目の引数は取得したいURL、2つ目の引数は見慣れない形式かもしれませんが、 リクエストのmethodはGETで、読み込みが完了したらarchivePageLoadedという関数が呼ばれるように指定していると解釈してください。
そして、読み込み完了時に呼ばれるarchivePageLoaded関数内で<div id="archive-datebased">から<div class="archive-category">の間にあるaタグのhref属性を 取り出しています。
その関数のコードは以下のようになっています。
var archiveUrls = [];
........
function archivePageLoaded(r)
{
    var text = r.responseText;
    text = text.replace(/[\r\n]/g, "");
    var pattern = '<div id="archive-datebased">(.*?)<div class="archive-category">';
    var re1 = new RegExp(pattern, "i");
    text.match(re1);
    var dataRange = RegExp.$1;
    var re2 = new RegExp(BLOG_URL+"[0-9]{4}/[0-9]{2}/index.html", "gi");
    archiveUrls = dataRange.match(re2);
}
まず、引数のrは、XMLHttpRequestオブジェクトです。
そのresponseTextプロパティによって、取得したHTMLソースを取得します。
次に、2行目で改行を削除しています。 この後も正規表現が度々出てきますが、色々なサイトで詳しく解説されていますので、ご存知ない方は検索してみていただきたいのですが、簡単に言えば 指定したパターンにマッチした文字列を取り出すことが出来る便利なものです。 3行目では正規表現パターンを定義しています。<div id="archive-datebased">と<div class="archive-category">の間の文字列を後で取り出すために( )でグループ化しています。
そして、4行目・5行目でHTML文字列から正規表現パターンのマッチングを行い、6行目のRegExp.$1でマッチした中の1つ目のグループの文字列(3行目の正規表現パターンの( )内の文字列)を取り出しています。
これで、ようやく<div id="archive-datebased">と<div class="archive-category">の間のHTML部分を取り出せました。
この取り出したHTMLに目的のURLが
http://wildcat.cocolog-nifty.com/web/yyyy/mm/index.html
というパターンで記述されていますので、7行目のように
http://wildcat.cocolog-nifty.com/web/数字4文字/数字2文字/index.html
というパターンでマッチングを行い、あらかじめ定義してあったarchiveUrlsという配列に結果を格納しています。

これで、めでたく月別にアーカイブされた記事のURLを取得することが出来ました。
明日は、このURLを使って各月の記事が書かれたHTMLを取得し記事を検索する仕組みを書きたいと思います。

| | コメント (0) | トラックバック (0)

2006年6月21日 (水)

JavaScriptで記事の検索

ブログ始めたばかりでイマイチ勝手がわかってませんが、ココログって記事の検索が出来なさそうですね。
何とかならないものかとココログの管理ページとかソースとか見ていると、ブログのルートにあるarchives.htmlから月別のHTMLファイルのリンクを 取り出せば、どうやら全ての記事をたどれそうでした。
そこで、Ajaxと正規表現で記事を検索するスクリプトを作成してみましたので、試しに設置してみます。
今は記事が少ないので検索も早いですが、記事が増えた時に使い物になるかどうかはわかりません。
が、検索できないよりはマシかな。
あと、半ば勢いで作ったことと、動作確認が不十分なため、動かないブラウザもあると思います。
特にMacでは全然見てないので、ダメかもしれません。(私はMacを持っていないのです・・・。Macの方、スミマセン)
まあ、ベータ版ってことで勘弁してください。少しずつ改良はしていこうと思ってます。
一応、WindowsのIE6とFirefox1.5では動作確認していますが、「俺の環境じゃ動かねぇよ」って方、よろしければコメントいただけると助かります。

| | コメント (2) | トラックバック (0)

2006年6月17日 (土)

【HTML】Conditional Comments

今日、たまたま職場で話が出たので、Conditional Commentsについて書こうと思います。
例えば、画面にアルファチャンネル付PNGを表示したい場合、IE6以下ではそのまま表示することは 出来ませんのでCSSでIE独自のフィルタを使うことになります。(IE5はそれでもダメだったかな...?)
でも、Firefoxとかは標準でサポートしているので、そんな必要はありません。
つまり、IEの指定バージョンにのみCSSファイルを読ませればよいわけですが、そんな時にこの Conditional Commentsが役に立ちます。
CとかC#とかがわかる方は、プリプロセッサを思い浮かべていただければ早いと思います。
具体的には以下のように書きます。
<link rel="stylesheet" type="text/css" href="style.css">

<!--[if IE 6]>
  <link rel="stylesheet" type="text/css" href="style-ie6.css" />
<![endif]-->

上のlinkタグは普通にすべてのブラウザに認識されますので、共通のスタイルを定義しておきます。
下のlinkタグは、コメント内にありますのでIE以外には認識されませんが、IEはこれを認識して 条件に合っていれば中に書いてあるHTMLが有効になります。
IE独自のCSSファイルを作成して、style.cssで定義しているクラス名と同じクラス名を定義してIE特有のスタイルを記述することで スタイルは上書きされ、IEにのみIE独自のスタイルを設定できるという感じです。
書式は以下のようになっています。
<!--[if expression]> ..... <![endif]-->
以下に簡単な例を示します。
まず、普通にアルファチャンネル付のPNGを表示してみましょう。

上の画像は、2枚のPNGが重なっています。
上の画像は半透明なのですが、IE6でご覧の方には青い背景の上に赤い四角が表示されていると思います。
FirefoxやOperaでご覧の方には、ちゃんと下の画像が透けて見えていると思います。
以下のようなHTMLを記述しています。
<div style="width:443px;height:262px;background-image:url(back.png);padding:0px;
  border:solid 1px black;">
  <div style="width:443px;height:262px;background-image:url(layer.png);
    background-repeat:no-repeat;padding:0px;margin:0px;"></div>
</div>

今度は、IE6のみ正しく表示されるようにConditional Commentsを使って記述してみましょう。

今度は、IE6の方は、ちゃんと赤い四角の下に画像が透けて見えていると思いますが、それ以外の方は赤い四角の画像が表示されていないと思います。
こちらは以下のようなHTMLです。
<div style="width:443px;height:262px;background-image:url(back.png);padding:0px;
  border:solid 1px black;">

  <!--[if IE 6]>
  <div style="width:443px;height:262px;
    filter: progid:DXImageTransform.Microsoft.
    AlphaImageLoader(src='layer.png',sizingMethod=scale);
    background-repeat:no-repeat;padding:0px;margin:0px;"></div>
  <![endif]-->

</div>
表示の関係上、途中で折り返してますのでちょっと見辛いですが、よくよく見てみると、中のdivタグの
background-image:url(layer.png);
が、
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='layer.png',sizingMethod=scale);
に変わっているだけですね。
つまり、IEにはIE独自のCSSであるfiler: ....の部分を設定すればよいことになります。
したがって、style.cssには、
div.alpha_image
{
    width:443px;
    height:262px;
    background-image:url(layer.png);
    background-repeat:no-repeat;
    padding:0px;
    margin:0px;
}
と記述しておき、style-ie6.cssには
div.alpha_image
{
    background-image:none;
    filter: progid:DXImageTransform.Microsoft.AlphaImageLoader
      (src='layer.png',sizingMethod=scale);
}
のように記述し、以下のように<head>~</head>内に記述すれば、
<link rel="stylesheet" type="text/css" href="style.css">

<!--[if IE 6]>
  <link rel="stylesheet" type="text/css" href="style-ie6.css" />
<![endif]-->

IEでは後の設定が上書きされ設定されるため、IEでもFirefoxでもアルファチャンネル付PNGを綺麗に表示できるようになります。 外部スタイルシートをインクルードする順序が重要です。今回のような場合は、IE独自のものは後でインクルードしてください。
このように、JavaScriptなどを使ってブラウザを判定しなくてもHTMLレベルで設定することも可能な場合もありますので、知っていて損はないと思います。

参考資料
About Conditional Comments(MSDN)

| | コメント (3) | トラックバック (0)

2006年6月15日 (木)

JavaScriptをFireBugでデバッグ

JavaScriptのデバッグって結構面倒ですよね。
alertで値を確認したりして。
タイマーで定期的に呼び出される関数内に、うっかりalertを仕込んで悲しい思いをしたことありませんか?
そんな時は、FireBugをお試し下さい。
気になる場所にブレイクポイントを設定して、ステップ実行しながら値を確認したり、Spy++でウィンドウを選択する時のように HTMLの要素をマウスで部分的に選んでソースを見たりすることが出来ます。
XMLHttpRequestの通信も見れますので、Ajaxを使った開発にも役立つ存在ではないでしょうか。
Firefoxのアドインなんですが、非常にオススメです。
以下のリンクよりダウンロード出来ます。
FireBug :: Mozilla Add-ons :: Add Features to Mozilla Software

追記:FireBugのインストールと使い方を簡単に書いてみましたので、そちらもご覧下さい。
FireBugのインストールと簡単な使い方

| | コメント (0) | トラックバック (0)

2006年6月14日 (水)

【JavaScript】クラスを定義する

昨日は、定義済みのオブジェクトにメソッドを追加して機能を拡張する方法を書きましたが、JavaScriptでも、C#やJavaのクラスのようなものを独自に定義することが出来ます。
具体的には、以下のように関数を定義して、その関数を拡張するような感じになります。
そして、この関数そのものがコンストラクタとなります。
function MyClass(n)
{
    //プロパティ
    this.name = n;
	
    // メソッド
    MyClass.prototype.copy = function(){
        var tmp = new MyClass(this.name);
        return tmp;
    };
}

var myClass = new MyClass("ClassA");
....
myClass.name = "ClassB";
var myClass2 = myClass.copy();
....
また、クラスの継承のようなことも出来ますが、その辺りはまた後日書きたいと思います。

| | コメント (0) | トラックバック (0)

2006年6月13日 (火)

【JavaScript】オブジェクトの機能を拡張する

JavaSciptには、オブジェクトのインスタンスに動的にメソッドを追加出来るという特徴的な機能があります。
まずは以下のコードを見てみます。
var str = new String("JavaScript");

str.left = function(n){
    return this.substr(0, n);
}

alert(str.left(4));

var str2 = new String("JavaScript");
alert(str2.left(4));
JavaScriptの文字列にはleftというメソッドはありませんが、str.left = function...の部分でstrというインスタンスに対してメソッドを追加しています。
これによって、alert(str.left(4));では"Java"と表示され、左からn文字を取り出すleftというメソッドが機能していることを確認できます。
しかし、このメソッドはあくまでも変数strに格納されているインスタンスに対して追加したものですので、その後のstr2.left(4)はエラーとなってしまいます。
これはこれで使い道はあるのですが、strだけでなくstr2でも同様に使えるようにしたい事も多いですよね。
そのような場合には、以下のようにしてStringという型(型という表現が適切かどうかわかりませんが...)に対してメソッドを追加できます。
String.prototype.left = function(n){
    return this.substr(0, n);
}

var str = new String("JavaScript");
alert(str.left(4));

var str2 = new String("JavaScript");
alert(str2.left(4));
prototypeというものが出てきましたが、prototypeというプロパティはJavaScirptのオブジェクト全てが持っていて、このprototypeプロパティに メソッドを追加することで、その型のインスタンスメソッドを定義することが出来ます。
従って、この例では、strもstr2も無事にleftメソッドを呼び出すことが出来ます。

前回のaddEventListener・removeEventListenerサンプルをこの機能を使って書き直したサンプルを作成しましたので、動作を確認してみてください。
サンプルページ

| | コメント (1) | トラックバック (0)

2006年6月11日 (日)

【JavaScript】 イベントリスナーの追加と削除

先日書いたイベントハンドラを追加する方法でも イベントをハンドリング出来ますが、この方法でセット出来る関数は1つだけです。
しかし、例えばObserverパターンのように複数のオブジェクトに対してイベントを通知したい場面も多いと思います。
そういう場合、DOM Level2 Event Modelをサポートしているブラウザをターゲットとしているなら、addEventListener・removeEventListener メソッドを使って以下のようにイベントリスナーの追加と削除を行います。
// イベントリスナー
function targetClicked()
{
    ....
}

var eventTarget = document.getElementById("ex1");
// リスナーの追加
eventTarget.addEventListener("click", targetClicked, false);

// リスナーの削除
eventTarget.removeEventListener("click", targetClicked, false);
しかし、もっともシェアの高いInternet Explorerがこれをサポートしていません。 Internet Explorerには同様の機能としてattachEvent・detachEventというメソッドが用意されていますので、 こちらを使用します。
// イベントリスナー
function targetClicked()
{
    ....
}

var eventTarget = document.getElementById("ex1");
// リスナーの追加
eventTarget.attachEvent("onclick", targetClicked);

// リスナーの削除
eventTarget.detachEvent("onclick", targetClicked);
従って、どちらのブラウザにも対応するには、以下のようにメソッドが存在するかを判別した上で行う必要があります。
// イベントリスナー
function targetClicked()
{
    ....
}

var eventTarget = document.getElementById("ex1");
// リスナーの追加
if(eventTarget.addEventListener){
    eventTarget.addEventListener("click", targetClicked, false);
}else if(eventTarget.attachEvent){
    eventTarget.attachEvent("onclick", targetClicked);
}

// リスナーの削除
if(eventTarget.removeEventListener){
    eventTarget.removeEventListener("click", targetClicked, false);
}else if(eventTarget.detachEvent){
    eventTarget.detachEvent("onclick", targetClicked);
}

サンプルを作成しましたので、実際に動作を確認してみてください。
サンプルページ
IEとFirefoxで比較すると、同様にイベントリスナーが呼び出されますが、呼び出される順序が違う点に注意が必要です。

参考資料
Document Object Model (DOM) Level 2 Events Specification(W3C)
attachEvent Method(MSDN Library)
detachEvent Method(MSDN Library)

| | コメント (0) | トラックバック (0)

2006年6月 9日 (金)

【JavaScript】 DOMのメソッド・プロパティ

JavaScriptからHTML要素にアクセスする時はDOMを使用しますが、私自身がよく忘れるので、そこそこ使用頻度の高いメソッド・プロパティのプチリファレンスを書いておきたいと思います。

Documentのメソッド
Element createElement( tagName[string] )
説明:新しいElementオブジェクトを生成します。
引数:タグの名前を文字列で指定します。
戻り値:新たに生成されたElementオブジェクト
var elem = document.createElement("img");
NodeList getElementsByTagName( tagName[string] )
説明:タグの名前を指定して要素のリストを取得します。
引数:タグの名前を文字列で指定します。
戻り値:該当する要素のリスト。
var elements = document.getElementsByTagName("img");
Element getElementById( id[string] )
説明:id属性を指定して要素を取得します。
引数:id属性値を文字列で指定します。
戻り値:該当する要素。
var element = document.getElementById("ex1");
NodeList getElementsByName( name[string] )
説明:name属性を指定して要素のリストを取得します。
引数:name属性値を文字列で指定します。
戻り値:該当する要素。
var elements = document.getElementsByName("ex1");
Elementのプロパティ・メソッド
string nodeName
説明:要素の名前を取得します。読み取り専用です。
var name = document.getElementById("ex1").nodeName;
string nodeValue
説明:要素の値を取得します。読み取り専用です。
var value = document.getElementById("ex1").nodeValue;
Node parentNode
説明:親要素を取得します。読み取り専用です。
var parent = document.getElementById("ex1").parentNode;
NodeList childNodes
説明:子要素のリストを取得します。読み取り専用です。
var elements = document.getElementById("ex1").childNodes;
Node firstChild
説明:先頭の子要素を取得します。読み取り専用です。
var element = document.getElementById("ex1").firstChild;
Node lastChild
説明:最後の子要素を取得します。読み取り専用です。
var element = document.getElementById("ex1").lastChild;
Node previousSibling
説明:前の要素を取得します。読み取り専用です。
var element = document.getElementById("ex1").previousSibling;
Node nextSibling
説明:次の要素を取得します。読み取り専用です。
var element = document.getElementById("ex1").nextSibling;
string tagName
説明:タグの名前を取得します。読み取り専用です。
Node insertBefore( newNode[Node], refChild[Node] )
説明:このメソッドを使用すると、子要素を挿入する際に、挿入する場所を指定できます。
引数:newNode:挿入する要素、refChild:この要素の前に挿入されます。
戻り値:挿入された要素。
Node removeChild( oldChild[Node] )
説明:指定した子要素を削除します。
引数:削除する子要素。
戻り値:削除された子要素。
Node appendChild( newChild[Node] )
説明:子要素を要素リストの最後に追加します。
引数:追加する子要素。
戻り値:追加された子要素。
boolean hasChildNodes()
説明:子要素を持っているか調べることができます。
戻り値:子要素を持っていればtrue、そうでなければfalse。
Node cloneNode( isDeep[boolean] )
説明:要素をコピーします。
引数:trueを指定するとディープコピーとなり、falseならシャローコピーとなります。
戻り値:新たにコピーされた要素。
void removeAttribute( name[string] )
説明:属性を削除します。
引数:属性名。
string getAttribute( name[string] )
説明:属性の値を取得します。
引数:属性名。
戻り値:属性の値。
void setAttribute( name[string], value[string] )
説明:属性をセットします。
引数:name:属性名、value:属性値。
NodeList getElementsByTagName( name[string] )
説明:タグの名前を指定して、要素のリストを取得します。
引数:タグの名前を文字列で指定します。
戻り値:該当する要素のリスト。
var element = document.getElementById("ex1");
var elements = element.getElementsByTagName("img");
boolean hasAttribute( name[string] )
説明:要素が、指定した名前の属性を持っているかどうかを調べられます。
引数:調べたい属性名。
戻り値:持っていればtrueを返します

参考資料
Document Object Model (DOM) Level 1 Specification (W3C)
Document Object Model (DOM) Level 2 Core Specification (W3C)

| | コメント (0) | トラックバック (1)

2006年6月 7日 (水)

【JavaScript】 イベントハンドラをセットする

要素がクリックされた時の処理を設定したい場合、例えば
<div onclick="hoge();">....</div>
のようにタグの属性で関数を指定することが出来ますが、以下のようにしてJavaScriptからも設定することが出来ます。

function elementClicked()
{
    alert("クリックされました!");
}

document.getElementById("ex").onclick = elementClicked;

また、あらかじめ関数を定義していなくても、

document.getElementById("ex").onclick = function()
{
    alert("クリックされました!");
};

のように、無名関数をセットすることも出来ます。
ページのロードが完了した際の処理も同様に、

window.onload = function()
{
    ......
};

と記述することが出来ます。

| | コメント (0) | トラックバック (0)

2006年6月 6日 (火)

【JavaScript】 動的に要素を変更してみる

HTML要素の参照を取得したら、次は見た目や中身を変更してみましょう。

1.中身を変更する
div・spanなど、HTML要素には中に別の要素が入れ子になっている場合が多いですが、この入れ子になっている中身を変更することが出来ます。

-- HTML --
<div id="ex1">.....</div>

-- JavaScript --
document.getElementById("ex1").innerHTML = "変更後の文字列です";
document.getElementById("ex1").innerHTML = "<b>タグも書き込めます</b>";

何かを実行した時に注意を促すメッセージを表示する場合などに使用できます。

2.見た目を変更する
要素の表示スタイルを動的に変更することが出来ます。
以下は枠線の色を変更するサンプルです。

-- HTML --
<div id="ex2" style="width:100px;height:100px;border:solid 1px black;"></div>

-- JavaScript --
document.getElementById("ex2").style.borderColor = "red";

要素のstyleプロパティ以下には、CSSで定義されている属性と同じ名前のプロパティが用意されていて、これを変更することで表示スタイルを変更できます。
※ CSS属性で、例えばborder-colorなどハイフンで区切られているものについては、JavaScriptではborderColorといった具合にハイフンが無くなり代わりにハイフンの後の1文字目が大文字になるという風になっています。

3.画像を入れ替える
imgタグにはsrcというimgタグ特有の属性がありますが、これらのタグの属性も変更可能です。
以下は、画像を変更するサンプルです。

-- HTML --
<img id="ex3" src="example1.gif">

-- JavaScript --
document.getElementById("ex3").src = "example2.gif";

小さなサムネイル画像をクリックされたら大きな画像に変更する、といったことが出来ます。

| | コメント (0) | トラックバック (0)

2006年6月 5日 (月)

【JavaScript】 要素を取得する

ここ1~2年の間にDynamic HTMLが多くの場所で利用されるようになりました。
Dynamic HTMLは、ページをリロードすることなく要素の外観を変えたり中身の文字を
変えたりすることが出来ますが、変更したい要素を取得しないと始まりません。
そこで、まず最初は、要素(HTML内のタグ)を取得する方法について書きたいと思います。

1.IDを指定して取得する
 HTML内の要素にはIDを付けることが出来ますが、そのIDを指定して要素を取得する方法です。
 まず、以下のようにタグにIDを付けます。
 <div id="test">DIVタグです</div>
 そして、このDIV要素を取り出すJavaScriptは、以下のようになります。

document.getElementById("test")

 試しに、以下のJavaScriptを実行してみてください。
 「DIV」と表示されたらOKです。

alert(document.getElementById("test").tagName);

 ただし、このようにして取得する場合は、複数の要素に同じIDをつけてはいけません。

2.タグの名前を指定して取得する
 "DIV"などのタグの名前で要素の配列を取得することが出来ます。
 配列となっているのは、ページ内にDIVタグがいくつあるかわからないためです。
 
 以下のようなタグがあったとします。
 <div>1つ目のDIVタグです</div>
 <div>2つ目のDIVタグです</div>
 これらを取得するJavaScriptは、以下のようになります。

 document.getElementsByTagName("div")

 Elementsとなっている点に注意してください。
 試しに、以下のJavaScriptを実行すると、

alert(document.getElementsByTagName("div").length);

 「2」と表示されると思います。
 lengthは、配列の数を取得するプロパティです。
 すべての要素にアクセスするには、以下のようにループを使います。

var elements = document.getElementsByTagName("div");
for(i=0;i<elements.length;i++){
    alert(elements[i].innerHTML);
}

| | コメント (0) | トラックバック (0)

2006年6月 4日 (日)

ブログ始めました

いまさらながら、ブログをやってみようと思います。
ASP.NETとJavaScriptを中心に、Web開発のメモを書いていきます。

| | コメント (0) | トラックバック (0)

トップページ | 2006年7月 »