7cc@はてなブログ

JavaScriptとかとか

選択中文字列の取得 ブラウザによる違い

Selection.toString() と Range.toString()

選択範囲には次の2つの方法がある。

getSelection.toString()
getSelection.getRangeAt(0).toString()

この2つで得られる文字はブラウザによる差が結構ある。

大まかな違い

  • 基本的には、Selectionは見た目通りの文字を返しやすく、Rangeはソースの文字を返す傾向にある。
  • Firefoxでは改行が \r\n になる
  • FirefoxGoogle Chromeは似ているが、 input, textareaで他と異なる

Selection.toStirng()

  • IE以外
    • selectionは見た目を反映する
  • IE
    • selectionでも見た目を反映しにくい。
    • Selectionからは改行コード、00A0を得られない。
    • script, style, display: none など不可視要素の文字まで含まれてしまう。
    • IE10まで使える document.selection.createRange().text の方が見た目を反映する度合は高いが(Firefoxのselectionと結果が近くなる)不可視要素の文字が含まれてしまう点は同じ。
      やっぱりIEを捨てれば楽だね!)

Range.toStirng()

  • Rangeの中に含まれているノードの文字を返す。
  • ソースの文字を反映する。
  • ブラウザ間の差が小さい。

見た目の反映とは

例えば次のようなhtmlがあった時 Selection.toStringの結果は、IE以外は改行など実際の表示が反映された文字が返る。

<p>abc</p><p>def</p>
IE以外 IE
abc
\n
\ndef
abcdef

具体的な違い

不可視要素

scriptやstyleを含む場合

中身(インラインのスクリプト・スタイル)が含まれるか

String FF GC IE
Selection no no yes
Range yes yes*1 yes

*1 bodyの直前にあるのは含まれない。

display: none

String FF GC IE
Selection no no yes
Range yes yes yes

scriptなども不可視要素なので同じ結果になるのは当たり前といえばそう

見た目上の改行を起こす要素

<br>

<p>abc<br>def</p>

<br>は文字に変換されるか、消える

String FF GC IE
Selection \r\n \n -
Range - - -

ブロックレベル要素

htmlソースの改行、インデントが変換される

  <p>abc
  <p>def
String FF GC IE
Selection 見た目の改行が\r\nに 見た目の改行が\nに 左下に同じ
Range ソースの改行が\nに, インデントが空白に 左に同じ 左下に同じ

そのままの結果

Selection : abc\n\ndef  
Range     : abc\n  def

入力要素

先に用語の説明

active
フォーカスがある状態、入力文字が直接選択されている状態
選択範囲内
選択範囲にその要素が含まれている状態
次のHTMLでtextareaをまたぐa-bを選択している時の状態
<p>a
<textarea>12345</textarea>
<p>b

input (type=text)

String FF GC IE
Selection - active -
Range - - -

textarea

String FF GC IE
Selection 選択範囲内 active 選択範囲内
Range 選択範囲内 選択範囲内 選択範囲内

button

String FF GC IE
Selection - 選択範囲内 選択範囲内
Range 選択範囲内 選択範囲内 選択範囲内

その他

u+00A0(&nbsp;)を含む場合

String FF GC IE
Selection 0020 \xA0 0020
Range \xA0 \xA0 0020

調査に使ったコード

function getTextInfo(text) {
  return Array.prototype.map.call(text, function(e){
                return e + "=" + e.charCodeAt(0)
              }).join(",")
}


document.onmouseup = function() {
  var sel = getSelection()
    , selText = sel.toString()
    , rangeText = sel.rangeCount ? sel.getRangeAt(0).toString() : ""

  ;[selText, rangeText].forEach(function(e){
    console.log(getTextInfo(e))
  })
}

横に置いておくと便利な文字コード

文字 10 16
\r 13 0x000D
\n 10 0x000A
space 32 0x0020
nbsp 160 0x00A0

複数のwindow

iframe, frameなどは window.getSelection には含まれない。
そのウィンドウがアクセス可能ならば window.name.getSelection から個別に取得可能