contenteditable要素に対してplaceholder設定を実現する

*GoogleChrome30.0.1573.2 dev(Mac版)でのみ動作確認しています。*

HTML5の機能として提供される`placeholder`属性ですが、とてもとても残念な事に`input`タグのみで`contenteditable=true`の要素に対してはその効果を適用出来ません。

そんな中で、inputタグでplaceholderを利用して初期値を表示している箇所と、`<div contenteditable=true>`を利用して入力可能にしている場所があると、当然ユーザーから

> 『あれ、ここ(inputタグ)で表示してるこの初期表示をあそこ(contenteditable=true)にも表示できるようにしてよ』

とか言われる訳です。というか言われますよね?。私は言われました。
そこで懇切丁寧に説明して理解してくれるユーザーさんならいいんですが、
往々にして『仕様です！実装してください』とか言われる訳です。

## 完成予想図
以下の様に設定出来るようにjQueryプラグインとして実装を行います。

```html
<head>
    <style type="text/css" media="screen">
      [data-placeholder][data-placeholderactive=true]::before {
        content: attr(data-placeholder);
        opacity: 0.5;
      }
    </style>
    <script src="jquery.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript" charset="utf-8">
      $(function() {
        $.setPlaceholder();
      });
    </script>
</head>
<body>
    <!-- placeholder有効時 -->
    <div contenteditable="true" data-placeholder="初期値" data-placeholderactive="true">
    </div>
    <!-- placeholder無効時 -->
    <div contenteditable="true" data-placeholder="初期値" data-placeholderactive="false">
    </div>
    <!-- あるいは -->
    <div contenteditable="true" data-placeholder="初期値">
    </div>
</body>
```

## レシピ
HTML5(jQueryではありません)の`data属性`と、CSSの`content`を利用します。

### data属性
HTML5のdata属性に関しては、ここで説明するよりもHTML5.jpの[独自データ属性](http://www.html5.jp/tag/attributes/data.html)辺りを見る方が100倍詳しく分かります。超簡単に言うと、`data-*`という属性を利用して独自データを定義出来るようになります。

### contentプロパティ
CSSの`content`は[MDNのCSSリファレンス](https://developer.mozilla.org/ja/docs/Web/CSS/content)辺りが参考になるかと思います。こちらも超簡単に言うと、指定したセレクタに対して任意の文字や画像の挿入を行う事が出来るようになります。

contentプロパティには様々な設定を行う事が出来ますが、その中で`attr`という物が存在します。
MDNのリファレンスから引用すると…

> 要素の属性の値 X を文字列として返します。属性 X が存在しない場合は、空文字が返されます。

と書かれています。つまりattrはHTMLの属性を指定する事が出来るという訳です。
なんと、この属性はdata属性の場合でも設定する事が可能です。

今回はこれを利用してplaceholder機能を実現します。

## 調理開始

### CSSの設定
CSSでは属性として`data-placeholder`及び`data-placeholderactive`が指定されていた要素が存在する場合に`:before`で`content`属性としてその要素の持つ`data-placeholder`を差し込む設定を行っています。
ここでは先ほどの完成予想図の通りのsytle設定をします。

```css
[data-placeholder][data-placeholderactive=true]::before {
    content: attr(data-placeholder);
    opacity: 0.5;
}
```
### HTMLの設定
完成予想図で書いた通りです。そのまま設定をします。
ここではdivタグで設定していますが、どんなタグでも問題ありません。
但し`contenteditable=true`に限定していないのでその点だけ注意が必要です。

```html
<div contenteditable="true" data-placeholder="初期値" data-placeholderactive="true">
```

### Javascriptの設定
CSSの設定とJavascriptの設定をしておけば、初期値としてplaceholderの表示までは行えます。但しこの設定だと当然フォーカスがあってもplaceholderは自動では消えません。そこでjavascriptでユーザーにより入力されたタイミングでplaceholderを削除するように実装を行います。

```javascript
/**
 * ContetEditable領域に対するplaceholderを実現するための簡易なjQueryプラグインを提供します
 */
(function(jQuery) {
  /**
   * Placeholderが`無効`になった場合のイベントハンドラ
   */
  var inActiveHandler = function() {
    delete(this.dataset.placeholderactive);
  };

  /**
   * Placeholderが`有効`になった場合のイベントハンドラ
   */
  var activeHandler = function() {
    if (this.innerText.length !== 0) return;
    this.dataset.placeholderactive = 'true';
  };

  //=======================================================
  // 公開メソッド
  //=======================================================

  /**
   * 属性として`data-placeholder`を保持する要素に対して一括でplaceholder設定を行います。
   */
  jQuery.setPlaceholder = function() {
    $('[data-placeholder]').placeholder();
  };

  /**
   * 指定した要素にplacehodler要素をCSSのcontent属性を利用して設定します
   */
  jQuery.fn.placeholder = function() {
    this.on('change keydown keypress input', inActiveHandler)
        .on('blur', activeHandler);

    // 初期化時に再評価
    activeHandler.bind(this.get()[0])();

    return this;
  };
})(jQuery);
```

あとは、適当なタイミングで`$.setPlaceholder()`を呼び出します。
今回のサンプルだと、入力領域でキーボードを操作したタイミングでplaceholderが非表示になり、入力領域からフォーカスが外れたタイミングで何も入力されていなければplaceholderが復元します。

### TODO
ちゃんとjQueryプラグイン化する。

作った => https://github.com/hikaruworld/jquery.contenteditable.placeholder

### 参考サイト
* [Faking a placeholder Attribute for an Editable div, and Some CSS Tricks
](http://blogs.teamb.com/craigstuntz/2013/01/29/38734/)