こんな感じ。
HogePage.js
// HogePage.html を制御するオブジェクトを生成します。
function HogePage()
{
// Fuga ボタンです。
this._fugaButton = document.getElementById("_fugaButton");
// Piyo ボタンです。
this._piyoButton = document.getElementById("_piyoButton");
// Fuga テキストボックスです。
this._fugaTextBox = document.getElementById("_fugaTextBox");
this._registerEventHandlers();
return this;
}
/* Static Members { */
HogePage.piyo = "Piyo";
/* } Static Members */
/* Methods { */
// 各イベントハンドラを登録します。
HogePage.prototype._registerEventHandlers =
function()
{
var _this = this;
this._fugaButton.onclick = function(){_this._fugaButton_Click();};
this._piyoButton.onclick = function(){_this._piyoButton_Click();};
};
// ふがふがします。
HogePage.prototype._fugaFuga =
function()
{
alert("Hello " + this._fugaTextBox.value + "!!");
};
// ぴよぴよします。
HogePage.prototype._piyoPiyo =
function()
{
alert("Hello " + HogePage.piyo + "!!");
};
/* } Methods */
/* Event Handlers { */
// Fuga ボタンのクリック時に呼び出されます。
HogePage.prototype._fugaButton_Click =
function()
{
this._fugaFuga();
};
// Piyo ボタンのクリック時に呼び出されます。
HogePage.prototype._piyoButton_Click =
function()
{
this._piyoPiyo();
};
/* } Event Handlers */
// ページのロード時に HogePage オブジェクトを生成します。
this.onload =
function()
{
new HogePage();
};
要は、ページに対応する JavaScript を一つのオブジェクトにまとめたという感じ。
イベントハンドラの登録が少し遠回りなコードになってしまったのが残念。
ちなみに、これと対になる HogePage.html はこんな。
HogePage.html
<?xml version="1.0" encoding="shift_jis"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>Hoge</title>
<script type="text/javascript" src="HogePage.js"></script>
</head>
<body>
<input id="_fugaTextBox" type="text"/>
<button id="_fugaButton">Fuga</button>
<button id="_piyoButton">Piyo</button>
</body>
</html>
あと、僕の以前の書き方は、このブログの JS ファイルを見るとわかる通り、少し強引に C# っぽく書いていた ^^; ( つーか、Setting~メソッド重複部分多すぎ・・・なんでこんな重複コードを平然と書いてるんだオレ・・・w )
概要
動作環境
試してみる
使い方
DecorationContextについて
Download
【 概要 】
ソースコードの装飾を行います。
ソースコードの装飾が動的に行われるため、Webサイトにソースコードを掲載する際に、わざわざ手作業で装飾する必要がなくなります。
現在の所、C#コードの装飾、JavaScriptコードの装飾、XMLの装飾をサポートしています。
また、自分で装飾の規則を作成することもできます。 ( 指定した正規表現にマッチする箇所に対して、文字色・背景色の着色,太字指定,下線指定,フォントサイズ指定,フォントファミリ指定ができます。 )
【 動作環境 】
動作確認済みのブラウザは以下のブラウザになります。その他のブラウザでの動作は未確認です。
- Internet Explorer 6.0
- Internet Explorer 7.0
- FireFox 1.5
【 試してみる 】
テストページを用意しました。
入力エリアにソースコードを入力し、装飾タイプを設定後、実行ボタンをクリックしてみてください。
TextDecoration.js テストページ
【 使い方 】
[ HtmlDecoratorのインスタンス化 ]
まず、YokoKen.TextDecoration.HtmlDecoratorクラスを引数なしでインスタンス化します。
var decorator = new YokoKen.TextDecoration.HtmlDecorator();
[ DecorationContextの生成 ]
DecorationContextについてを参照してください。
[ HtmlDecoratorオブジェクトにDecorationContextオブジェクトを設定 ]
HtmlDecoratorオブジェクトのsetDecorationContextメソッドを使って、DecorationContextオブジェクトを設定してやります。
decorator.setDecorationContext(context);
[ 装飾 ]
装飾したい文字列を引数に指定してdecorateメソッドを使うと、装飾されて戻ってきます。
var textbox1 = document.getElementById("textbox1");
var text = textbox1.value;
var decorationText = decorator.decorate(text);
decorateメソッドに渡す文字列は、HTML化された文字列ではなく、純粋な文字列を渡してください。(ようするに、実体参照とか改行タグとかダメです。)
YokoKen.TextDecoration.HtmlDecorator クラスのparseHtmlToTextという静的メソッドを使えば、実体参照や改行タグを含んだ文字列を純粋な文字列に変換してくれます。(改行タグ以外のタグは含めないで下さい。改行タグ以外は無視します。)
var div1 = document.getElementById("div1");
var text = YokoKen.TextDecoration.HtmlDecorator.parseHtmlToText(div1.innerHTML);
var decorationText = decorator.decorate(text);
【 DecorationContextについて 】
DecorationContextクラスは、装飾規則を表すクラスです。
現在の所、このDecorationContextの生成方法には、以下の方法があります。
[ 予め用意されている着色規則を利用する ]
YokoKen.TextDecoration.Specialized.DecorationContextFactoryオブジェクトのメソッドを使用して、予め用意されているDecorationContextオブジェクトを生成することができます。
現状、このオブジェクトには、以下の3つのメソッドが用意されています。
- createCSharpDecorationContextメソッド ( C#コード装飾用のDecorationContextオブジェクトを生成 )
- createJavaScriptDecorationContextメソッド ( JavaScriptコード装飾用のDecorationContextオブジェクトを生成 )
- createXMLDecorationContextメソッド ( XML装飾用のDecorationContextオブジェクトを生成 )
[ XMLファイルに記述する ]
独自の装飾規則を、XMLファイルに記述して利用することができます。
XMLファイルには、装飾する箇所を示す正規表現の指定、文字色・背景色の着色,太字指定,下線指定,フォントサイズ指定,フォントファミリ指定ができます。 ( もう少し詳しい解説が欲しいという方は、この記事にコメントしてください。 )
XMLファイルに記述する際は、 DecorationContext XMLスキーマ に従う必要があります。( アップローダの都合でファイル名の末尾に".txt"が付加されています。ローカルに保存後、ファイル名末尾の".txt"を削除してください。 )
以下、参考までに。( ローカルに保存後、ファイル名末尾の".txt"を削除してください。 )
C#コードの装飾規則 XMLファイル
JavaScriptコードの装飾規則 XMLファイル
XMLコードの装飾規則XMLファイル
作成したXMLファイルを利用するには、YkoKen.TextDecoration.DecorationContext.createInstanceFromXmlメソッドを使用します。
var context = YkoKen.TextDecoration.DecorationContext.createInstanceFromXml("CSharp.xml");
decorator.setDecorationContext(context);
【 DownLoad 】
TextDecoration.js
※ 使用する際は、直リンクせず、自分のWebサイトにTextDecoration.jsを配置して使用してください。
前回の記事でほんの少し書いたが、プライベートメソッド内に記述されたthisキーワードは、通常はwindowオブジェクトを参照してしまう。
< そもそもthisキーワードって? >
thisキーワードは、コンテキストオブジェクト を参照するためのキーワードである。
thisキーワードがwindowオブジェクトを参照するということは、その関数のコンテキストオブジェクトがwindowオブジェクトであるということになる。
< なぜコンテキストオブジェクトがwindowオブジェクトになってしまうのか? >
これは、プライベートメソッドの 呼び出し方 に原因がある。
プライベートメソッドは、プライベートフィールドに対して関数を設定することで定義できると、前回説明した。そうすると、プライベートメソッドの呼び出し方は
this.privateMethod1():
や、
obj.privateMethod1();
といった、インスタンス経由での呼び出し方はできないので、
privateMethod1();
という、直接的な呼び出し方になる。
この呼び出し方をすると、その関数のコンテキストオブジェクトがwindowオブジェクトになってしまうのである。 ( むしろ、コンテキストオブジェクトがwindowオブジェクトなのが普通であり、インスタンス経由で呼び出した時が特殊な動作をしている。これについてはこの記事の最後で。 )
< プライベートメソッドのコンテキストオブジェクトを、期待通りにするには? >
これには、Functionオブジェクトの applyメソッド 、または callメソッド を利用する。
applyメソッドとcallメソッドは、コンテキストオブジェクトを指定して関数を実行することができる。
function Hoge()
{
var privateMethod1 =
function()
{
return this;
};
this.privilegedMethod1=
function()
{
var obj1 = privateMethod1(); // windowオブジェクトが返される。
var obj2 = privateMethod1.apply(this); // Hogeオブジェクトが返される。
};
}
applyメソッドとcallメソッドの違いは、関数に渡す引数の指定方法のみである。
applyメソッドは、第一引数でコンテキストオブジェクトを受け取り、第二引数で関数に渡す引数の配列を受け取る。
callメソッドは、第一引数でコンテキストオブジェクトを受け取り、第二引数以降で関数に渡す引数を受け取る。
function fuga(arg1, arg2)
{
}
var context = new Object();
var arg1 = 1;
var arg2 = 2;
var args = [arg1, arg2];
fuga.apply(context, args); // applyは第二引数に配列で指定する。
fuga.call(context, arg1, arg2); // callは第二引数以降に指定していく。
< 呼び出し方が原因ということは・・・ >
実は、パブリックメソッドやプレビレッジドメソッドも、同じ呼び出し方をすれば、コンテキストオブジェクトがwindowオブジェクトになる。
function Hoge()
{
}
Hoge.prototype.publicMethod1 =
function()
{
return this;
};
var hogeObj = new Hoge();
var obj1 = hogeObj.publicMethod1()) // 当然、hogeObjを返してくる。
var func = hogeObj.publicMethod1; // publicMethod1自体をfuncに入れる。
var obj2 = func() // func()という風に呼び出すと、windowオブジェクトを返してくる。
< インスタンス経由での呼び出しは暗黙的に・・・ >
this.メソッド名() や、 インスタンス名.メソッド名() といった、インスタンス経由での呼び出し方をすると、そのインスタンスがコンテキストオブジェクトとなる。しかし、applyやcallも使わず、普通に関数を呼び出した場合、コンテキストオブジェクトはwindowオブジェクトとなる。
つまり、インスタンス経由での関数呼び出しは、暗黙的にコンテキストオブジェクトを指定して実行されるのである。 ( 内部でapplyやcallを呼び出しているのか、applyやcallに実装されている処理を直接行っているのかどうかは知らないけど。。。 )
ただし、”クラスベース”のオブジェクト指向言語 ( C#やJavaなど ) ではなく、”プロトタイプベース”のオブジェクト指向言語である。
以下、JavaScriptでのOOPについての簡単な解説。
【 コンストラクタ 】
オブジェクトの雛形は " コンストラクタ " と呼ばれる関数として定義する。これは、クラスベース オブジェクト指向言語の " クラス " に相当する。コンストラクタは関数なので、普通の関数と同じように呼び出すこともできる。 ( 普通、そんな使い方はしないけど。 )
コンストラクタからオブジェクトを生成するには、new 演算子を用いる。
// Hogeコンストラクタ
function Hoge()
{
}
// Hogeオブジェクト生成
var hogeObj = new Hoge();
[ thisキーワード ]
コンストラクタ内 ( と、後述するインスタンスメソッド内 ) では、thisキーワードによって、コンストラクタのインスタンスを参照することができる。
ただし、プライベートメソッド内では、通常は、コンストラクタのインスタンスではなくwindowオブジェクトを参照してしまうので注意。( 詳細はこちらの記事 )
【 インスタンスフィールド 】
インスタンスフィールドは2種類に大別できる。
[ パブリックフィールド ]
パブリックフィールドには、インスタンスの外部からアクセスすることができる。
定義するには、コンストラクタ内で、そのコンストラクタのインスタンスに対して動的にフィールドを追加する。
function Hoge()
{
this.publicField1 = 0;
}
[ プライベートフィールド ]
プライベートフィールドには、インスタンスの外部からアクセスすることができない。また、パブリックメソッド ( 後述 ) からもアクセスすることができない。
定義するには、コンストラクタ内で、varキーワードによる変数宣言を行う。また、コンストラクタの引数リストも、プライベートフィールドとなる。
function Hoge(arg1, arg2) // arg1とarg2もプライベートフィールド
{
var privateField1 = 0;
}
なお、プライベートフィールドは、 this.[ プライベートフィールド名 ] といった参照の仕方ができないので注意。参照するには直接プライベートフィールド名を記述する。
【 インスタンスメソッド 】
インスタンスメソッドは3種類に大別できる。
[ パブリックメソッド ]
パブリックメソッドには、インスタンスの外部からアクセスすることができる。また、パブリックメソッド内から、プライベートなメンバにアクセスすることはできない。
定義するには、コンストラクタのprototypeプロパティ ( 詳細はそのうち... ) に格納されているオブジェクトに、メソッドを追加する。
function Hoge()
{
}
Hoge.prototype.publicMethod1 =
function()
{
};
prototypeプロパティに格納されているオブジェクトに対してメソッドを追加するため、パブリックメソッドとなる関数オブジェクトは、ソースコードのロード時に一度だけ生成される。
[ プレビレッジドメソッド ]
プレビレッジドメソッドには、インスタンスの外部からアクセスすることができる。また、プレビレッジドメソッド内から、プライベートなメンバにアクセスすることができる。
定義するには、コンストラクタ内でインスタンスフィールドに関数オブジェクトを設定する。
function Hoge()
{
this.privilegedMethod1 =
function()
{
};
}
コンストラクタ内で自分自身のパブリックフィールドにメソッドを追加するので、プレビレッジドメソッドとなる関数オブジェクトは、コンストラクタ実行 ( インスタンス化 ) のたびに生成される。
[ プライベートメソッド ]
プライベートメソッドには、インスタンスの外部からアクセスすることはできない。また、プライベートメソッド内から、プライベートなメンバにアクセスすることができる。
定義するには、コンストラクタ内でプライベートフィールドに関数オブジェクトを設定する。
function Hoge()
{
var privateMethod1 =
function()
{
};
}
コンストラクタ内で自分自身のプライベートフィールドにメソッドを追加するので、プライベートメソッドとなる関数オブジェクトは、コンストラクタ実行 ( インスタンス化 ) のたびに生成される。
【 静的メソッド 】
静的メソッドは必ずパブリックになる。インスタンスフィールドやインスタンスメソッドにはアクセスすることができない。
定義するには、コンストラクタ関数自体のインスタンスフィールドに関数オブジェクトを設定する。前述したように、コンストラクタは、それ自体が ( 関数 ) オブジェクトである。
function Hoge()
{
}
Hoge.staticMethod1 =
function()
{
};
【 オブジェクトを直接表記 】
以前書いた記事を参照
【 参考 】
Collection & Copy - JavaScriptにおけるプライベートメンバ
特定の実体参照ってのは、以下の4つ。
[ 実体:" " ]
< [ 実体:"<" ]
> [ 実体:">" ]
& [ 実体:"&" ]
この4つを除く実体参照がinnerHTMLに設定されても、実体に置換されてしまう。
JavaScriptからではなく、HTMLに直接記述した場合も同様。
この4つの実体参照をinnerHTMLに設定した場合は、実体参照のまま設定されるのだが、
を除く3つの実体参照は、その実体をinnerHTMLやinnerTextに設定した場合も、
実体参照に置換されて設定される。 ( ただし、"&"に関しては、実体としてinnerHTMLに設定することはできない。 )
なお、数値文字参照 ( 例えば、< [ 実体:"<" ] ) を指定しても、文字実体参照 ( この場合、< ) に置換される。
検証コードvar div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
var div4 = document.getElementById("div4");
div1.innerHTML = ""ω"; // これらは実体に置換される。
div2.innerHTML = "\"ω"; // そのまま。
div3.innerHTML = "<>&"; // そのまま。
// ↓だと&を設定できない。
// div4.innerHTML = "<>&";
div4.innerText = "<>&"; // これらは実体参照に置換される。
alert(div1.innerHTML);
alert(div2.innerHTML);
alert(div3.innerHTML);
alert(div4.innerHTML);
ちなみに、HTMLに直接記述した場合にも、同様の処理が適用される。
[ 参考 ]
実体参照 - Wikipedia
Wikipedia:特殊記号 - Wikipedia
JSONとはJavaScript Object Notationの略で、JavaScriptとの親和性が非常に高いデータ交換フォーマットである。
詳しくは↓
The application/json Media Type for JavaScript Object Notation (JSON)
Introducing JSON (→日本語翻訳ページ)
JSON in JavaScript (→日本語翻訳ページ)
JSONは、前回の記事で書いたオブジェクトの表記方法を応用している。
種を明かせば、例のオブジェクト表記方法を文字列化してデータのやり取りを行い、JavaScriptのeval関数でJavaScriptコードに変換(=オブジェクトに変換)するという仕組み。eval関数にJSONを渡す際は、JSONを文字列"()”で囲む必要がある。
ただ、気をつけなければいけない点がいくつか。
- プロパティ名(リンク先に倣えば"名前")は、文字列として記述すること。
- オブジェクト(リンク先に倣えば”値”)には、数値,Boolean値,文字列,null参照、またはこれらのみで構成される配列,オブジェクトのみ許可されている。当然だけど関数はダメ。
eval関数の性質上、これらを無視してもオブジェクトに変換することはできるが、極端な話それはJSONとは言えない。
ちなみに、JSONファイルの拡張子は.jsonである。
JSON形式のファイルを記述する例を以下に記述する。
Hoge.json{
"piyo": "test",
"hogera":
{
"foo": true,
"bar": [10, 20, 30, 40, 50]
}
}
Hoge.jsonをJavaScriptコードで扱う例を以下に記述する。
Hoge.jsonを扱う例function jsonControlSample(json)
{
var hoge = eval("(" + json + ")");
var message = "";
message += hoge.piyo + "¥r¥n";
message += hoge.hogera.foo + "¥r¥n";
for (var i = 0; i < hoge.hogera.bar.length; i++)
{
message += hoge.hogera.bar[i] + "¥r¥n";
}
alert(message);
}
なお、eval関数は文字列をJavaScriptのコードに変換(して実行)する関数であるため、受け取ったJSONの中身が実は危険なJavaScriptコードを文字列化したものであったりしても、そのままコードが実行されてしまう。冒頭のリンク先にも書いてある通り、eval関数を用いるより、json.jsのJSON parserを使用した方が安全である。json.jsには、JavaScriptのオブジェクトをJSONに変換するJSON stringifierも含まれている。
オブジェクトは通常どおり、数値やBoolean値ならそのまま記述、文字列ならダブルクォーテーションで囲んで記述、配列なら[]の中にカンマ区切りでオブジェクトを記述、関数ならfunction(){}の形式で記述する。{[プロパティ名]: [オブジェクト], ...}の形式のオブジェクトも当然含ませることができる。
以下に例を記述。
オブジェクトを直接記述する例var obj1 =
{
p1: 1,
p2: "1",
p3:
[
{
p1: "a1",
p2: "a2"
},
{
p1: "b1",
p2: "b2"
}
],
m1:
function()
{
alert(this.p1 + this.p2);
},
m2:
function()
{
var message = "";
for (var i = 0; i < this.p3.length; i++)
{
message += this.p3[i].p1 + "," + this.p3[i].p2 + "¥r¥n";
}
alert(message);
},
m3:
function(arg1)
{
alert(arg1);
}
}
obj1.m1();
obj1.m2();
obj1.m3("test1");
Windows Script Debuggerは以下のリンク先からダウンロードできる。
ダウンロードの詳細 : Windows Script Debugger
インストール後、IEの [ ツール ] - [ インターネット オプション ] - [ 詳細設定 ] にて、 [ スクリプトのデバッグを使用しない (Internet Explorer) ] のチェックを外しておく必要がある。
Windows Script Debuggerにより、自分が開発しているASP.NETプロジェクトのJavaScriptはもちろん、それ以外のサイトのJavaScriptもデバッグすることができ、ステップ実行,ブレークポイント,ウォッチ,クイックウォッチなど様々なデバッグ機能が使用できる。
自分が開発しているASP.NETプロジェクトのJavaScriptをデバッグするには、まずサーバーコードをデバッグする時と同じようにデバッグ開始を行う。ページが表示されたら、IEの [ 表示 ] - [ スクリプト デバッガ ] - [ 開く ] を実行する。これにより、ブレークポイントの貼られたJavaScriptコードに到達した時に中断されるようになる。ブレークポイントを貼るのは、デバッグ開始を行う前・後どちらでもよい。
なお、 [ 表示 ] - [ スクリプト デバッガ ] - [ 次のステートメントで中断 ] を実行すれば、次にJavaScriptコードが実行されるタイミングで一時中断させることができる。
Windows Script Debuggerのドキュメントへのリンク
Microsoft Scripting Technologies
Hoge.jsをインクルードする場合に、HTMLに記述するタグ<script type="text/javascript" src="Hoge.js"></script>
jsファイルが別のjsファイルを利用する場合は、通常、以下のように記述する。
Hoge.jsがFoo.jsを利用する場合に、HTMLに記述するタグ<script type="text/javascript" src="Foo.js"></script>
<script type="text/javascript" src="Hoge.js"></script>
これで問題はないのだが、どうせならjsファイル自身に、インクルードのためのコードを含めてしまいたい。だが、JavaScriptにそのような構文は用意されていない。そこでどうするかというと、以下のように、”別のjsファイルをインクルードするためのHTMLのタグ”を出力するコードをjsファイルに記述すればよい。
Hoge.jsがFoo.jsを利用する場合に、Hoge.jsに記述するコードdocument.write("<script type=\"text/javascript\" src=\"/WebSite1/Foo.js\"></script>");
この時、scriptタグのsrc属性に指定するパスを絶対パスにしておけば、Hoge.jsを利用するHTMLがHoge.jsと同じ階層のディレクトリにあろうが違う階層のディレクトリにあろうが関係なく、正常に動作する。
このHoge.jsを利用するHTMLでは、Hoge.jsのインクルードのみ行えばよい。