IE9でvalueを使わずにplacholderを表示する

IE9 向けに placeholder を提供するライブラリをいくつか試してみたものの、どうもしっくり来るものがなく、自前で実装したのでメモ。
ただし、やっつけ実装なので、あくまでも実現方法の参考として見て頂きたい。

### 試したライブラリ
- [Placeholders.js](https://jamesallardice.github.io/Placeholders.js/)
- [HTML5 Placeholder jQuery Plugin](https://github.com/mathiasbynens/jquery-placeholder)
- [Placeholder Enhanced](https://github.com/dciccale/placeholder-enhanced)
- [jQuery ah-placeholder Plugin](https://github.com/ahomu/jquery.ah-placeholder)

#### 既存ライブラリのイマイチポイント [^1]
- ページをリロードすると placeholder が表示されなくなる
- placeholder と同じテキストを入力できない (勝手に placeholder と判断されて削除される)
- 何も入力していない状態で submit すると placeholder の内容が submit される

[^1]: 具体的にどれがどのライブラリに該当したかは失念


### 実装コード

```js
$(function() {
  var isPlaceholderSupported = (function() {
    return 'placeholder' in document.createElement('input');
  }());

  if (isPlaceholderSupported) {
    return;
  }
  $('[placeholder]')
    .wrap('<div style="display:inline-block;position:relative"></div>')
    .parent()
      .on('mouseover', function() {
        var parent = $(this);
        var elm = parent.find('span');
        var input = parent.find('[placeholder]');
        elm.css('cursor', input.css('cursor'));
      })
      .end()
    .each(function() {
      var elm = $(this);
      var text = elm.attr('placeholder');
      var val = elm.val();
      var paddingTop = Number(elm.css('padding-top').replace('px', ''));
      var paddingLeft = Number(elm.css('padding-left').replace('px', ''));
      var borderTop = Number(elm.css('border-top-width').replace('px', ''));
      var borderLeft = Number(elm.css('border-left-width').replace('px', ''));

      $('<span style="color:#999;display:inline-block;position:absolute"></span>')
        .text(text)
        .css({
          top: paddingTop + borderTop,
          left: paddingLeft + borderLeft,
          visibility: (val === '' ? 'visible' : 'hidden')
        })
        .insertBefore(elm);
    })
    .on('focus', function() {
      $(this).prev().css('visibility', 'hidden');
    })
    .on('blur', function() {
      var elm = $(this);
      if (elm.val() === '') {
        elm.prev().css('visibility', 'visible');
      }
    })
    .prev()
      .on('mousedown', function() {
        var elm = $(this);
        var input = elm.next();
        if (input.prop('disabled') || input.prop('readonly')) {
          return;
        }
        elm.css('visibility', 'hidden');
        input.focus();
        return false;
      })
    ;
});
```

コード適用時のHTMLイメージ:

```html:適用前
<input type="text" placeholder="値を入力してください" />
```
```html:適用後
<div style="display:inline-block; position:relative">
  <span style="left:2px; top:3px; color:#999; display:inline-block; position:absolute; cursor:auto">値を入力してください</span>
  <input type="text" />
</div>
```

### 工夫ポイント

- placeholder をサポートしているブラウザではそちらを使用するようにしている。
- value を使う代わりに span を input 上に重ねて表示する方式のため、リロードや submit しても input の内容に影響を与えない。
- placeholder が input の内容と同じ位置に表示されるよう、input の padding、border を考慮している。
- input と同じカーソルを placeholder に設定するようにしている。[^2]
- placeholder にフォーカスが当たらないよう、placeholder の onmousedown で input にフォーカスを設定している。

[^2]: [Bootstrap](https://getbootstrap.com/) を使っていると、input を無効にした場合のスタイルが用意されているので

### やっつけポイント

- jQuery に依存している。[^x1]
- スタイルが style 属性にハードコーディングされている。[^x2]
- input を勝手に div で囲むため、場合によってはスタイルが崩れる。[^x3]
- input と placeholder のスタイル (フォントサイズ等) が微妙に違う[^x4]
- 毎回、input や placeholder の Element を取得している。(`prev()` とか) [^x5]
- コードのコピペが多い (`prev()` とか placeholder の表示切替部分とか) [^x6]
- input ごとにイベントを登録している。 [^x7]

[^x1]: 実装が楽だったので…。 頑張ればネイティブメソッドのみでも実装できるはず
[^x2]: ちゃんとクラスを用意して、そちらにスタイルを適用するべきでしょうね
[^x3]: 適用先の HTML にあわせて個別カスタマイズしてもらうということで…
[^x4]: これも個別カスタマイズで吸収ということで…
[^x5]: きちんと placeholder 用のクラスを用意して、そこに保持した方が良いかと
[^x6]: これもきちんとオブジェクト指向すれば解消できるはず
[^x7]: `$(document).on('イベント', '要素', ハンドラ)` を使った方が省エネのはず

### 結論
IE9 をサポートしなくて良いように根回ししましょう。