JavaScript メモ

JavaScript? に関するメモを追記していく。

IEとFirefoxの違い

Firefoxの方がW3C勧告に忠実なようだけど、IEのシェアもいまだに大きい以上は無視できない(事実上標準)。

DOM扱いの相違

相違点を追記していく。

  • タグで囲まれる文字列(CDATA)を取得するには、Firefoxでは textContent、IEではinnerText。(nodeValue ならどちらでもOK)
  • childNode のとり方が違う。Firefoxは空白ノードをカウントする。IEはカウントしない。
    参考-> DOM入門 子ノードの取得

Script実装の相違

相違点を追記していく。

  • inputタグなどの onchange イベントのタイミングが違うっぽい。
    これが気になる場合は onclick などで代替。
  • IEのonclickなどでsubmitする場合は、最後に return false をしないと、ソケットエラー(Firefoxなら書かなくても大丈夫)。
  • IEではタグに勝手にいろんな属性を追加できる(divタグにvalueをつけたりとか)が、Firefoxではそれを取得できないことがある。
    確実に拡張属性をとるなら、getAttribute()で。
  • イベントを追加するには、IEはattachEvent()、FirefoxはaddEventListener?()。

参考

IEでJavaScript?をデバッグ

ブラウザの設定を有効にする

IEの「インターネットオプション」->「詳細設定」タブを開いてその中の「ブラウズ」カテゴリから「スクリプトのデバッグを使用しない(Internet Explorer)」というチェックがあるので、このチェックを外す(デフォルトでチェックがONになっている)。

ただ、これは Microsoft Office がインストールされている必要があるかも?

Windows Script Debugger を使う

Windows Script Debugger を使う。

Internet Explorer Developer Toolbar を使う。

最近(といっても2007年5月)出たフリーのデバッグツール。IE6と7に対応している。 Firebug のような感じで使えるので、WSD より使いやすいかも。 ただ、ScriptやDOM、CSSなどの値をインスペクトすることはできるが、 Firebugのように変更して確認することはできないっぽい?

FirefoxでJavaScript?をデバッグ

Firebug を使う(お勧め)

これはかなり使いやすい。まずは下記ページからアドオンをインスコ。

「署名がありません」とかいわれるけど気にしない。

インストールされたらFirefoxを再起動。メニューの「ツール」に「Firebug」という項目が増えているのでここから「Open Firebug」を選択、「Enable Firebug」をクリックするとデバッグが開始される。ブラウザで動作を見ながらステップ実行できるので、非常にやりやすい。

JavaScript? Debugger を使う

これはRADのような画面でScriptを追うツール。画面で確認する必要がなく、シンタックスや処理内容だけデバッグすれば良いときはこちらが良いのかも。

サンプル

フォーカスが当たると文字が消える

focusinput.js

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
-
|
-
|
|
!
!
 
-
|
-
|
|
!
!
    function removeText(formName,elementName){
        var target = document.forms[formName].elements[elementName];
        if(target.value == target.defaultValue){
            target.value = "";
            target.style.color='#000000';
        }
    }
 
    function insertText(formName,elementName){
        var target = document.forms[formName].elements[elementName];
        if(target.value == target.defaultValue || target.value == ""){
            target.value = target.defaultValue;
            target.style.color='#999999';
        }
    }

sample.html

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 
 
 
 
 
 
 
 
 
 
 
 
<html>
    <head>
        <title>sample</title>
        <script type="text/javascript" src="focusinput.js"></script>
    </head>
    <body>
        <form name="form1">
            <input type="text" size="50" onfocus="removeText(this.form.name,this.name);" 
            onblur="insertText(this.form.name,this.name);" maxlength="256" value="入力してください" style="color: #999999;">
        </form>
    </body>
</html>

submit でボタンを無効にする

こちらのを参考に、再表示で元に戻す処理も追加してみた。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
-
-
|
!
|
-
|
-
-
|
-
|
!
|
|
!
!
!
|
-
-
-
|
!
!
!
|
-
|
-
|
-
-
-
-
|
|
!
!
!
!
!
|
-
|
-
-
|
-
|
!
|
!
!
!
|
-
-
|
-
|
-
|
!
!
|
-
-
|
-
|
-
|
!
!
!
 
 
var DisableSubmit = {
    init: function() {
        this.addEvent(window, 'load', this.onLoad());
    },
    
    onLoad: function() {
        var self = this;
        return function () {
            for (var i = 0; i < document.forms.length; ++i) {
                var elements = document.forms[i].getElementsByTagName('input');
                if (!elements || elements.length == 0) {
                    continue;
                }
                self.setDisable(elements, false);
                self.addEvent( document.forms[i], 'submit', self.onSetDisable(elements, true) );
            }
        }
    },
 
    setDisable: function(elements, flag) {
        for (var i = 0, element; element = elements[i]; i++) {
            if (element.type == 'submit') {
                element.disabled = flag;
            }
        }
    },
    
    onSetDisable: function(elements, flag) {
        var self = this;
        return function () {
            self.setDisable(elements, flag);
            // see: http://support.microsoft.com/kb/890981/ja
            if (isIE && elements && elements.length > 0) {
                for (var j = 0; j < elements.length; j++) {
                    if (elements[j].type.toLowerCase() == 'file') {
                        self.onCancel();
                        break;
                    }
                }
            }
        }
    },
    
    onCancel: function() {
        var self = this;
        window.setTimeout(function() {
            for (var i = 0; i < document.forms.length; ++i) {
                var elements = document.forms[i].getElementsByTagName('input');
                if (!elements || elements.length == 0) {
                    continue;
                }
                self.setDisable(elements, false);
            }
        }, 1000);
    },
    
    addEvent: function(element, type, event) {
        if(element.addEventListener) {
            element.addEventListener(type, event, false);
        } else if(element.attachEvent) {
            element.attachEvent('on'+type, event);
        } else {
            element['on'+type] = event;
        }
    },
    
    removeEvent: function(element, type, event) {
        if(element.removeEventListener) {
            element.removeEventListener(type, event, false);
        } else if(element.detachEvent) {
            element.detachEvent('on'+type, event);
        } else {
            element['on'+type] = event;
        }
    }
}
 
DisableSubmit.init();

ただ、このままだと、submit後にページ遷移しないケース(問い合わせダイアログを開いてキャンセルした場合など)で ボタンが無効なままなので、onCancel() で元に戻すようにする。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
-
-
|
!
-
|
!
|
!
function confirm_msg(msg) {
    if(window.confirm(msg)){ 
        return true;
    }
    if(DisableSubmit){
        DisableSubmit.onCancel();
    }
    return false;
}

選択文字列をタグで括る

選択文字列の取得の仕方がFirefoxとIEとでちょっと違うので、やむを得ず判定を使う。

taginsert.js

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 
 
-
|
-
|
|
|
|
|
|
|
-
|
|
!
|
!
 
-
-
|
!
|
|
|
|
|
|
|
|
-
|
|
-
|
|
!
!
 
-
|
|
|
|
|
!
var isIE = (navigator.appName.toLowerCase().indexOf('internet explorer')+1?1:0);
 
function getAreaRange(obj) {
    var pos = new Object();
    if (isIE) {
        obj.focus();
        var range = document.selection.createRange();
        var clone = range.duplicate();
        clone.moveToElementText(obj);
        clone.setEndPoint( 'EndToEnd', range );
        pos.start = clone.text.length - range.text.length;
        pos.end = clone.text.length - range.text.length + range.text.length;
    } else if(window.getSelection()) {
        pos.start = obj.selectionStart;
        pos.end = obj.selectionEnd;
    }
    return pos;
}
 
function insertTag(textAreaId,tag_st,tag_ed) {
    //var target = document.forms[].elements[];
    //var target = window.opener.document.getElementById(textAreaName);
    var target = document.getElementById(textAreaId);
    if (target == null) 
        return;
    var pos = getAreaRange(target);
    var val = target.value;
    var range = val.slice(pos.start, pos.end);
    var beforeNode = val.slice(0, pos.start);
    var afterNode = val.slice(pos.end);
    var insertNode;
    if (range || pos.start != pos.end) {
        insertNode = '<' + tag_st + '>' + range + '</' + tag_ed + '>';
        target.value = beforeNode + insertNode + afterNode;
    } else if (pos.start == pos.end) {
        insertNode = '<' + tag_st + '>' + '</' + tag_ed + '>';
        target.value = beforeNode + insertNode + afterNode;
    }
}
 
function insertAnchor(textAreaId,url,target) {
    var tag_st = "a href=\"" + url + "\"";
    if (target != null && target != "")
        tag_st = tag_st + " target=\"" + target + "\"";
    var tag_ed = "a";
    insertTag(textAreaId, tag_st, tag_ed);
}

以下は、idが"edit"というテキストエリアにタグを挿入する例。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<script type="text/javascript">
function insertTest() {
    var url = document.frm.url.value;
    var tar = document.frm.target.value;
    insertAnchor('edit', url, tar);
}
</script>
 
<body>
    <form name="frm">
        <textarea id="edit"></textarea><br>
        <input type="text" name="url" size="50">
        <input type="text" name="target" size="12"><br>
        <input type="button" value="挿入" onclick="insertTest()">
    </form>
</body>

入力フィールドをクリアする

form の入力フィールド (input) を全て空白にするスクリプト。 そんなもん reset で良くね?と思ったアナタは罠にハマりますぜ。 reset というのはクリアするのでなく「初期値」に戻すのです。 なので、もし何かデフォルト値 (defaultValue) があったら、その値が再入力されるので、 reset = 真っ白にする、ということではないのです。

以下そのスクリプト。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
-
-
|
-
-
-
|
!
!
!
|
-
-
|
!
!
!
!
function clearFilelds() {
    for (var i = 0; i < document.forms.length; i++) {
        var fields = document.forms[i].getElementsByTagName('input');
        if (fields && fields.length > 0) {
            for(var j = 0; j < fields.length; j++) {
                if (fields[j].type.toLowerCase() == "text") {
                    fields[j].value = "";
                }
            }
        }
        var textareas = document.forms[i].getElementsByTagName('textarea');
        if (textareas && textareas.length > 0) {
            for(var j = 0; j < textareas.length; j++) {
                textareas[j].value = "";
            }
        }
    }    
}

submit 時にタグを decode

逆(submit 時にエスケープ)はよくあるけど、これはあんまりない。 というか使う機会もあまりないんですが。 submit するときに、エスケープされているタグを元に戻す処理。 WYSIWYG エディタを使ってるシーンなどで欲しくなることがあります。

以下、その処理だけど、途中 IE が分岐してあるのは、   というのは半角スペースを表現するコードなんだけど、 普通これは 20h に解釈されるべきなのに、 IE ではなぜか A0h で出力している為。これも罠だよね。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 
 
-
-
|
-
|
-
|
!
!
 
-
|
|
|
|
|
-
!
|
!
 
-
|
|
|
|
|
|
|
|
!
 
-
|
|
-
|
-
|
|
|
|
|
!
!
|
!
 
-
|
|
-
-
-
|
-
|
!
!
!
!
 
-
-
|
!
!
 
-
|
|
-
|
!
!
 
-
-
-
!
!
!
 
 
var isIE = (navigator.appName.toLowerCase().indexOf('internet explorer')+1?1:0);
 
function appendEvent(element, type, event) {
    if(element.addEventListener) {
        element.addEventListener(type, event, false);
    } else if(element.attachEvent) {
        element.attachEvent('on'+type, event);
    } else {
        element['on'+type] = event;
    }
}
 
function encodeHTML(val) {
    if (!val) return val;
    var dst = val;
    dst = dst.replace(/&/ig, "&amp;");
    dst = dst.replace(/</ig, "&lt;");
    dst = dst.replace(/>/ig, "&gt;");
    //dst = dst.replace(/"/ig, "&quot;");
    dst = dst.replace(/ /ig, "&nbsp;");
    return dst;
}
 
function decodeHTML(val) {
    if (!val) return val;
    var dst = val;
    dst.replace(/&nbsp;/ig, " ");
    dst.replace(/&quot;/ig, "\"");
    dst.replace(/&gt;/ig, ">");
    dst.replace(/&lt;/ig, "<");
    dst.replace(/&amp;/ig, "&");
    return dst;
}
 
function decodeHTMLForIE(val) {
    if (!val) return ;
    var dst = "";
    for ( var i = 0; i < val.length; i++ ) {
        var c = escape( val.charAt(i) );
        switch ( c ) {
            case '%26': dst = dst + "&"; break;//&amp;
            case '%3C': dst = dst + "<"; break;//&lt;
            case '%3E': dst = dst + ">"; break;//&gt;
            case '%A0': dst = dst + " "; break;//&nbsp;(%20)
            default : dst = dst + val.charAt(i); break;
        }
    }
    return dst;
}
 
function convertDatas() {
    var elements = document.getElementsByTagName('input');
    if (!elements) return;
    for (var i = 0; i < elements.length; i++) {
        if (elements[i].type.toLowerCase() == 'text' && elements[i].value) {
            if (isIE) {
                elements[i].value = decodeHTMLForIE(elements[i].value);
            } else {
                elements[i].value = decodeHTML(elements[i].value);
            }
        }
    }
}
 
function getSubmitFunction() {
    return function() {
        convertDatas();
    }
}
 
function initForms() {
    var forms = document.getElementsByTagName('form');
    if (!forms) return;
    for (var i = 0; i < forms.length; i++) {
        appendEvent(forms[i], 'submit', getSubmitFunction());
    }
}
 
function getInitFunction() {
    return function() {
        //initForms();
        convertDatas();
    }
}
 
appendEvent(window, 'load', getInitFunction());

改行挿入

普通の textarea なら Enter キーを押せば改行コードが挿入される。 それをボタンなりイベントなりでやるとこういうことになる。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
-
|
|
|
|
|
|
-
|
|
|
-
|
|
|
|
|
|
|
|
|
!
|
!
function insertReturn(target, code) {
    if( code != 13 )
        return;
    
    var val = target.value;
    var returnCode = "\n";
    
    if (isIE) {
        var sel = document.selection.createRange();
        sel.text = returnCode;
        sel.select();
    } else {
        var top = target.scrollTop;
        var pos = getAreaRange(target);
        var range = val.slice(pos.start, pos.end);
        var beforeStr = val.slice(0, pos.start);
        var afterStr = val.slice(pos.end);
 
        target.value = beforeStr + returnCode + afterStr;
        target.scrollTop = top;
        target.setSelectionRange(pos.start+1, pos.start+1);
    }
    target.focus();
}

数値チェック

isNaN()の逆。じゃあ !isNaN() で良いじゃないかと。 ブラウザや環境によってこのビルトイン関数が使えないみたいなので、正規表現で代替してみた。

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
-
-
|
!
|
-
|
!
|
!
function isNum(str) {
    if (!str) {
        return false;
    }
    if ( str.match(/^[+-]?[\d]+$/)
        || str.match(/^[+-]?[\d]+\.[\d]+$/) ) {
        return true;
    }
    return false;
}

スクリプトで画像の上下を反転させる

そんな無理しなくても、上下逆の画像をペイントか何かでつくればいいじゃん。 とか思ったら負け。

IE では filter が使えるので、FlipV で反転させる。 Firefox などのモダンブラウザはイメージオブジェクトが使えるので、それで。 canvas というタグもあるらしいけど、まだ対応してるブラウザが少なそう?

flipv.js

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
-
|
-
|
!
|
-
|
!
-
|
|
-
!
|
-
|
|
|
|
|
|
|
|
!
!
function flipV(id) {
    var canvas = document.getElementById(id);
    if (!canvas) {
        return ;
    }
    var imgSrc = canvas.getAttribute('src');
    if (!imgSrc) {
        return ;
    }
    if (navigator.appName.toLowerCase().indexOf('internet explorer')+1?1:0) {
        var imgNode = document.createElement('img');
        imgNode.setAttribute('src', imgSrc);
        //imgNode.style.filter = 'FlipH();';
        imgNode.style.filter = 'FlipV();';
        canvas.appendChild(imgNode);
    } else {
        var imgNode = document.createElement('canvas');
        var dc = imgNode.getContext('2d');
        var img = new Image();
        img.src = imgSrc;
        dc.rotate(Math.PI);
        dc.translate( -1 * img.width, -1 * img.height);
        dc.drawImage(img, 0, 0);
        canvas.appendChild(imgNode);
    }
}

flipv.html

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 
 
 
 
 
 
 
 
 
 
 
<html>
<head>
<title>flipV</title>
<script type="text/javascript" src="flipv.js"></script>
</head>
<body onload="flipV('canvas')">
 
<div id="canvas" src="sample1.jpg"></div>
 
</body>
</html>

IEか否かの最も簡単な判定

Everything is expanded.Everything is shortened.
  1
  2
  3
-
|
!
 function isIE() {
     return ( /*@cc_on!@*/false );
 }

MLEXP. Wiki


トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-02-16 (水) 01:43:43 (4982d)