innerHTMLを利用してリアルタイムHTMLエディタを作ってみましょう。
たいしたことはしていないわりに、見た目のおかげで、知らない人からはなんだかすごいことをしているように見られるという効果もあります。
とりあえず簡単にhtmlから
wisiwig.html
<html lang="ja"> |
2箇所にIDを指定しているだけでそれ以外は特に何もありません。
JavaScript的には毎秒openFile()を実行します。
というわけで肝心のwisiwigEdit()を書いてしまいましょう。
wisiwig.js
/*==========================================================*/ |
inputFieldが入力する部分、printFieldが表示する部分です。
inputFieldの値が変更されたら、printFieldにその値を表示します。
そのときにその値をinputFieldOldValueに保存しておきます。
次回inputFieldと比較して、変更されているかどうかをチェックします。
毎回過去のデータと比較しているのは単に負荷軽減のためです。
面倒ならinputFieldOldValueの部分は一切無視して実装しても特に問題はありません。
特にどこと通信しているわけでも入力値を使用しているないのでセキュリティ特に問題はなく、危険が及ぶにしても自分のブラウザだけなのですが、念のために<script>タグは無効にしておきます。
もっとも、それでも
<img src="javascript:alert('hello');">
<BR style=left:expression(eval('document.location="http://www.google.co.jp/";'))>
などと書かれたら反応してしまいますが。
これでひとまず完成です。
http://yuubiseiharukana.creativeroot.jp/js2/js2-2-1.html
何か文字を入力するだけでリアルタイムに表示が変更されるので、知らない人に作ってあげるとそこはかとなく尊敬されるかもしれません。
wisiwig.css
/*----------------------------------------------------------*/ /* 結果表示 */ #printField{ width:80%; margin-right:10%; margin-left:10%; border:1px solid #aaa; padding:5px; } /*----------------------------------------------------------*/ /* 入力テキストエリア */ #inputField{ background-color:#efe; } |
実用的なサブルーチンを作ってみましょう。
サブルーチンと関数はほぼ同義語なので今後混ざって出てきても気にしないで下さい。
ちなみにJavaScriptではクラスも関数とほぼ同義だったりします。
あらゆる言語で問題になるのが日本語対応です。
その第一が文字化けで、第二が全角半角の対応です。
全角の「0」と半角の「0」は当然ながら違う文字として認識されます。
そこで問題になるのがフォーム等の入力値です。
たとえば住所欄など、全角に統一して扱いたい入力欄があるとき、
よくある解決法のひとつが「半角文字が入っていたら入力させなおす」です。
しかしこれはユーザビリティ的には最悪です。
Atok等、数値記号は自動的に半角入力してくれるIMEを使用していた場合、そのようなフォームに突き当たったらわざわざ設定を変更しなければなりません。
そんな酔狂に付き合ってくれるユーザーは少ないでしょう。
全角半角変換程度のことはフォーム側で処理してあげるべきです。
さて、PHPではphp mb_convert_kanaという命令一発で非常に容易に変換できます。
PerlでもEncodeやjcodeというモジュールが用意されており簡単に使用できます。
しかし何故かJavaScriptには簡単に変換する方法が存在しません。
もっとも、さほど難しくはないので作ってしまいましょう。
とりあえず数値を半角から全角に変換するスクリプトです。
単純に、charAtを使用して、入力文字列に変換対象文字が見つかったら入れ替えているだけです。
convertInt.js
function convertInt(input){ var hanList = "0123456789"; var zenList = "0123456789"; var str = ""; var oneStr; var i; var c; var n; for(i=0;i<input.length;i++){ oneStr=input.charAt(i); n = hanList.indexOf(oneStr,0); c = n>=0 ? zenList.charAt(n) : oneStr; //三項演算子 str+=c; } return str; } |
使用時は、普通に
var output=convertInt(input);
と書くだけです。
さて、どちらかというと全角入力された英数字を半角に変換することが多いと思います。
どちらの場合でも使えるよう入力値に変換方向も書き加えてしまいましょう。
convertStr.js
function convertStr(input,flag){ |
var output=convertStr(input,true);
として使用します。
第二引数にfalseを設定すると半角を全角に変換し、それ以外だと全角から半角に変換します。
次回はこのライブラリを使用してフォームのバリデートを行ってみましょう。
XMLHttpRequestと直接は関係ありませんが、同時に使うことがほぼ前提になっているinnerHTMLについて解説しておきます。
JavaScript時計はよく見ますが、そのほとんどがinputタグ内に書かれたものです。
http://yuubiseiharukana.creativeroot.jp/ajax1/ajax1-2-1.html
document.forms[0].sampleWatch.value=new Date(); <input type="text" name="sampleWatch"> |
なにしろ実質的に上の2行で実現できるのですから非常にお手軽だと言わざるをえません。
リアルタイムに更新を行いたいときも、window.setTimeoutを仕込むだけです。
今後JavaScript部分は別ファイルに追い出すことになりますが、この程度なら同一ファイルでかまわないでしょう。
http://yuubiseiharukana.creativeroot.jp/ajax1/ajax1-2-2.html
<script type="text/javascript"> <!-- function openFile(){ document.forms[0].sampleWatch.value=new Date(); window.setTimeout("openFile();",1000); } --> </script> <body onload="openFile()"> <form> <input type="text" name="sampleWatch" size="60"> </form> </body> |
さて、フォーム時計はわかりやすいのはいいのですがデザイン的に困り者です。
cssでなんとかなるとはいえ、「今日は4月1日です」程度の文章がブロック要素で分断されてしまうのは何かと釈然としません。
どうにかしてインライン要素で表示しましょう。
getElementByIdというメソッドがあります。
HTMLタグのidプロパティを取得できます。
HTML内の適当な場所に
<div id="sampleWatchInc">さんぷる</div>
と入力した場合、
document.getElementById(sampleWatchInc);
と入力することで、その部分のオブジェクトを取得することができます。
さて、getElementByIdメソッドにはinnerHTMLというプロパティがあるのですが、上記の例で言うと具体的には<div>タグで挟まれた部分のことを示します。
というわけで
var node=document.getElementById(sampleWatchInc).innerHTML;
とするとnodeの中には"さんぷる"が入ります。
それはいいのですが、驚いたことに
document.getElementById(sampleWatchInc).innerHTML="ほげほげ";
と入力すると、<div>タグで囲まれた部分の「さんぷる」が「ほげほげ」に書き換えられてしまいます。
なんともあっさり文字列を変更できてしまいました。
さて、最後にリアルタイム時計と、よくある押すと文字が変更になるボタンを置いておきます。
forms.nameがgetElementById.innerHTMLに変わっただけなので、簡単にわかると思います。
http://yuubiseiharukana.creativeroot.jp/ajax1/ajax1-2-3.html
<script type="text/javascript" src="./ajax1-2-3.js"></script> <body onload="loadDate()";> <form> <input type="button" value="ボタンを押すと文字が変わる" onClick="changeText()"> </form> <div id="time">さんぷる</div><br /> <div id="disp">さんぷる</div> |
http://yuubiseiharukana.creativeroot.jp/ajax1/ajax1-2-3.js
var i=0; |
よく考えてみたらdivもブロック要素ですが。
Ajaxとは、ページ全体をリロードすることなくサーバとデータをやり取りし、
リアルタイムに画面表示を変更できるという素敵極まりない技術のことです。
XMLHttpRequestというクラスを用いて通信を行います。
さっそくですが実際に使ってみましょう。
とりあえずクラスなのでオブジェクトを作成します。
基本的にXMLHttpRequestで作成するのですが、
例によってIEは独自仕様なのでActiveXObjectを使用する必要があります。
var xxxxx=new XMLHttpRequest(); var xxxxx=new ActiveXObject("Microsoft.XMLHTTP"); var xxxxx=new ActiveXObject("Msxml2.XMLHTTP"); |
Microsoft.XMLHTTPはIEなら何れでも、Msxml2.XMLHTTPはIE6以降(Microsoft.XMLHTTPより速い)、XMLHttpRequestはIE7以降およびIE以外のブラウザで使用できます。
ブラウザ毎にページを分けるのも馬鹿らしいので簡単にまとめましょう。
if(window.XMLHttpRequest){ xxxxx=new XMLHttpRequest(); }else{ xxxxx=new ActiveXObject("Microsoft.XMLHTTP"); } |
え?両方とも対応してないブラウザ?そんなん知らんがな。
※正しく書くならこんなかんじ
var xxxxx = false; |
さてXMLHttpRequestクラスから作成したオブジェクトxxxxxに対して、
以下のようなメソッドやプロパティで操作を行うことができます。
今回はとりあえずテキストファイルを表示してみます。
xxxxx.open("GET","ajax.txt",true);
xxxxxオブジェクトに対し、ajax.txtをGETメソッドで取得するという命令を作成します。
あくまで作成するだけで実行はまだ行いません。
trueは非同期という意味で、返事を気にせずに次の行に突き進みます。
falseにすると非同期になり、ファイルの内容を取得するまで処理が止まります。
falseだとプログラムの処理は簡単になりますが、
Ajaxはリアルタイムであることに意味があるので、よほどのことがなければtrueでいきましょう。
xxxxx.send(null);
openメソッドで作成した命令を、実際に送信します。
パラメータを渡したい場合は()内に記入します。
今回はajax.txtのテキストファイルを取得するだけなのでnullです。
xxxxx.abort();
sendした命令を中止します。
サーバが落ちてていつまでも反応が返ってこないといった場合に使うべきなのですが、今回はまあテストなのでパス。
xxxxx.getAllResponseHeaders()
getResponseHeader("ラベル名")
返ってきたデータのヘッダを見ることが出来ます。
ETag、Content-Length、Keep-Alive、Content-Type、Last-Modified等が参照できます。
xxxxx.onreadystatechange
後述のreadyStateプロパティが変化するたびにイベントが発生するという超便利なイベントハンドラです。
xxxxx.onreadystatechange=checkState;
と記入するだけでreadyStateが変化するたびにcheckState関数を実行してくれます。
ただ、checkState(xxxxx)というふうに引数を渡すとエラーになります。
このせいでXMLHttpRequestオブジェクトがグローバル必須になってしまうのですが・・・何故。
xxxxx.readyState
sendで送ったリクエストが現在どんな状態か知ることができます。
0~4の5種類あります。2なら受信待ち、3なら受信中、等。
でもまあデータを全部受信したら4以外はあまり使いません。
xxxxx.status
xxxxx.readyStateでデータを全部取得した、と思ったら実は404NotFoundの応答を全部受信しただけだった、なんてことがあるわけで、応答の内容をstatusでチェックします。
200だと正常な応答、ということになります。
xxxxx.responseText
xxxxx.responseXML
実際に帰ってきたデータが入るところです。
TextかXMLかは返ってきたデータ形式で変わります。今回はテキストなので当然responseTextに入っています。
もちろんメソッドプロパティは他にもまだありますが、とりあえずはこんなところで。
さて、上記を纏めると以下のようになります。
http://yuubiseiharukana.creativeroot.jp/ajax1/ajax1-1-1.html
<script type="text/javascript"> |
適当にテキストファイルを作って同じフォルダに入れておいてください。
うまくajax.txtの取得に成功すると、アラートが表示されます。めでたし。
文字化けで上手く表示されない場合、ajax.txtの文字コードをUTF-8にしてください。
AjaxはUTF-8が前提にされています。
上記のとおり、xxxxx.onreadystatechange = checkStatus(xxxxx)
というふうにcheckStatus関数にオブジェクトを渡せないので
XMLHttpRequestオブジェクトはグローバルで作成する必要があります。今のところ。