WinIE の標準準拠モードで TextRange オブジェクト | にょきにょきのお勉強

WinIE の標準準拠モードで TextRange オブジェクト


ブラウザは DOCTYPE 宣言の違いにより、標準準拠モードか後方互換モードか解釈を変えて動作します。


特に WinIE ではその違いが結構顕著にみられるので、最近は標準準拠モードで作って Firefox でも WinIE でもあまり違わないレンダリングをしてもらおうという姿勢で臨んでいます。


私の周りでは XHTML1.0 Strict な DOCTYPE 宣言を xml 宣言なしで制作していることが多くて、私もコレを使っています。

(xml 宣言を付けると WinIE では後方互換モードになってしまう)

<DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<textarea>の中で選択されている文字列を JavaScript でごにょごにょしたくて、ブラウザが WinIE の時には TextRange オブジェクトを使って操作しようとしていたのですが、どういうわけか moveEnd() メソッドを呼んでいる部分までくると「予期しないメソッドの呼び出し、またはプロパティ アクセスです。コード: 0」 というエラーが起きてしまいます。


TextRange オブジェクトを作るまでは問題ないのにメソッドが呼べないという不可解なエラーを検索してみるもコレという情報を見つけられませんでした。


とにかく何が原因なのか探るべく、コードを最低限のところまで削っていきテストを繰り返しつぎの状況でエラーが起きているところまでは分かりました


1) WinIE で標準準拠モード

2) <div><form><textarea></textarea></form></div> という構造の HTML

3) 外側の<div>に css で position: absolute が設定されている

4) <textarea>に対して作ったTextRange オブジェクトの moveEnd("textedit") を呼ぶ


いろいろ削ったりしているので、なんのコードだ、、ってことになってますが再現用コードはこんな。

<!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
 " lang="ja" xml:lang="ja">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=shift_jis" />
        <meta http-equiv="Content-Script-Type" content="text/javascript" />
        <meta http-equiv="Content-Style-Type" content="text/css" />
        <title>Sample</title>
        <script>
          // <![CDATA[
          function get_select(txt) {
              txt.focus();
              var sel = document.selection.createRange();
              var rang = txt.createTextRange();
              rang.moveToPoint(sel.offsetLeft, sel.offsetTop);
              rang.moveEnd("textedit");

              if(rang.text.replace(/\r/g,"").length != 0){
                  var las = (txt.value.match(/(\r\n)*$/),RegExp.lastMatch.length);
                  txt.selectionStart = txt.value.length - (rang.text.length + las);
                  txt.selectionEnd = txt.selectionStart + sel.text.length;
                  alert(txt.value.substring(txt.selectionStart, txt.selectionEnd));
              }
          }
          // ]]>
        </script>

        <style>
            .dame {
                position: absolute;
            }
        </style>
    </head>

    <body>
        <div class="dame">
            <form action="hoge.cgi" name="fm">
                <textarea name="nexturl"></textarea><br />
                <a href="javascript:get_select(document.fm.nexturl);">選択</a>
            </form>
        </div>
    </body>
</html>

このままだと <textarea> 内のテキストを選択してから"選択"をクリックするとエラーになります。


後方互換モードにするとエラーはおきず、期待通り選択した範囲が alert で表示されます。

また、標準準拠モードでも <form> のすぐ外側の <div> の position: absoluete をやめるとエラーはおきず、期待通り。


そこで私の解決方法は、DOCTYPE 宣言を変えると見た目が変わってしまって困り、position: absolute は他のページと共有している css ファイルに書いてあり、position: static ではレイアウトが崩れる、、、という状況だったので、TextRange を使うページでだけ、<style> タグの中で position: relative を上書き設定することで回避しました。


ちなみにこのモードの違いはDOCTYPE スイッチという名前で呼ばれているみたいです。