忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/04/29 12:06 |
JavaScript2-3:リアルタイムHTMLエディタ

innerHTMLを利用してリアルタイムHTMLエディタを作ってみましょう。
たいしたことはしていないわりに、見た目のおかげで、知らない人からはなんだかすごいことをしているように見られるという効果もあります。

とりあえず簡単にhtmlから

wisiwig.html

<html lang="ja">
<head>
        <meta http-equiv="Content-Type" Content="text/html;charset=UTF-8">
        <link rel=stylesheet type="text/css" href="./wisiwig.css">
        <meta http-equiv="Content-Script-Type" content="text/javascript">
        <script type="text/javascript" src="./wisiwig.js"></script>
        <title>WISIWIGなエディタ</title>
        <script type="text/javascript">
        <!--
                function openFile(){
                        //WISIWIGエディタ
                        wisiwigEdit();
                        //1秒毎に実行
                        window.setTimeout("openFile();",1000);
                }
        -->
        </script>
</head>

<body onload="openFile()">
        <div id="inclementWatch"></div>
        <h2>WISIWIGなエディタ</h2><br />
        <form>
                <textarea rows="10" cols="100" id="inputField"></textarea>
                <br /><hr />
                <div id="printField" style="display:none;"></div>
        </form>
</body>
</html>


2箇所にIDを指定しているだけでそれ以外は特に何もありません。
JavaScript的には毎秒openFile()を実行します。
というわけで肝心のwisiwigEdit()を書いてしまいましょう。

wisiwig.js

/*==========================================================*/
//グローバル変数定義
var inputFieldOldValue="";

/*==========================================================*/
//メインルーチン

        /*----------------------------------------------------------*/
        /* WISIWIGエディタ作成 */
function wisiwigEdit(){

        //HTML入力部分取得
        var inputField        = document.getElementById("inputField");
        //結果表示部分取得
        var printField        = document.getElementById('printField');

                //検索文字列が空なら何も出力しない
                if (inputField.value==""){
                        printField.style.display = "none";

                        //検索文字が更新されたら
                } else if (inputField.value!=inputFieldOldValue) {

                        //改行コードを<br />に変換
                        var aaa=inputField.value.replace(/\r\n|\r|\n/g,"<br />");

                        //一部タグを削除するサブルーチン
                        aaa=subKillTag(aaa);
                        
                        //画面表示
                        printField.style.display = "block";
                        printField.innerHTML=aaa;
                                        
                }
        //古い内容を保存しておく
        inputFieldOldValue=inputField.value;
}

/*==========================================================*/
//サブルーチン
        /*----------------------------------------------------------*/
        /* 一部のタグを殺すサブルーチン */
        function subKillTag(text){
                
                //<script>タグ
                text=text.replace(/<(.*script.*)>/ig,"&lt;$1&gt;")
                
                /* 他にも殺したいものがあればここに記入 */
                
                //返却
                return text;
        }


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;
        }


PR


2008/05/22 19:52 | Comments(0) | TrackBack() | JavaScript
JavaScript1-2:全角半角変換関数

実用的なサブルーチンを作ってみましょう。
サブルーチンと関数はほぼ同義語なので今後混ざって出てきても気にしないで下さい。
ちなみに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 hanList = "0123456789";
        hanList += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        hanList += "abcdefghijklmnopqrstuvwxyz";
        hanList += "-+_@. /[]()'!~*;?:&=$,%#";
    var zenList = "0123456789";
        zenList += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        zenList += "abcdefghijklmnopqrstuvwxyz";
        zenList += "-+_@. /[]()’!~*;?:&=$,%#";

        if(flag == false){
             var tmp=hanList;
             hanList=zenList;
             zenList=tmp;
        }

    var str = "";
    var i;var c;var n;var oneStr;
    
    for(i=0;i<input.length;i++){
        oneStr=input.charAt(i);
        n = zenList.indexOf(oneStr,0);
        c = n>=0 ? hanList.charAt(n) : oneStr;
        str+=c;
    }
    return str;
}


var output=convertStr(input,true);
として使用します。
第二引数にfalseを設定すると半角を全角に変換し、それ以外だと全角から半角に変換します。

次回はこのライブラリを使用してフォームのバリデートを行ってみましょう。



2008/05/13 12:53 | Comments(0) | TrackBack() | JavaScript
JavaScript2-2:innerHTML

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;

function loadDate(){
    document.getElementById("time").innerHTML=new Date;
    window.setTimeout("loadDate();",1000);
}

function changeText(){

    var node=document.getElementById("disp");
    i=!i;
   
    if(i){
        node.innerHTML="押すたびに変更";
    }else{
        node.innerHTML="されます";
    }
}

 
よく考えてみたらdivもブロック要素ですが。



2008/04/25 17:38 | Comments(0) | TrackBack() | JavaScript
JavaScript2-1:XMLHttpRequest

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;

if(window.XMLHttpRequest) {
    // Firefox, Opera など
    xxxxx = new XMLHttpRequest();
    xxxxx.overrideMimeType('text/xml');
} else if(window.ActiveXObject) {
    // IE
    try {
        xxxxx = new ActiveXObject('Msxml2.XMLHTTP');
    } catch (e) {
        xxxxx = new ActiveXObject('Microsoft.XMLHTTP');
    }
}


さて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">
<!--
    //XMLHttpRequestオブジェクトはグローバルで指定
    var xxxxx;
    
    //メインルーチン
    function loadButton(){        
        //オブジェクトを作成
        xxxxx=createXmlHttpRequest();
        //リクエストを作成
        xxxxx.open("GET","ajax.txt",true);
        //readyStateが変更になるたびに実行される関数を指定
        xxxxx.onreadystatechange = checkStatus;
        //リクエストを送信
        xxxxx.send(null);
    }

    //readyStateが変更になるたびに実行される関数
    function checkStatus(){
        //受信完了したか、無事に受信できたか確認
        if(xxxxx.readyState == 4 && xxxxx.status == 200){
            alert(xxxxx.responseText);
        }
    }

    //HTTPリクエスト作成関数
    function createXmlHttpRequest() {
        var xmlhttp = false;
        if( window.XMLHttpRequest) {
            xmlhttp = new XMLHttpRequest();
        } else if(window.ActiveXObject) {
            try {
                xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
           } catch(e) {
                xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
           }
       }
    return xmlhttp;
    }

-->
</script>

<input type="button" value="ajaxテスト" onClick="loadButton()">


適当にテキストファイルを作って同じフォルダに入れておいてください。
うまくajax.txtの取得に成功すると、アラートが表示されます。めでたし。
文字化けで上手く表示されない場合、ajax.txtの文字コードをUTF-8にしてください。
AjaxはUTF-8が前提にされています。

上記のとおり、xxxxx.onreadystatechange = checkStatus(xxxxx)
というふうにcheckStatus関数にオブジェクトを渡せないので
XMLHttpRequestオブジェクトはグローバルで作成する必要があります。今のところ。



2008/04/24 13:09 | Comments(0) | TrackBack() | JavaScript

<<前のページ | HOME |
忍者ブログ[PR]