クリップボードから画像の貼り付け のバックアップ(No.2)

更新


公開メモ

pukiwiki のソース編集画面にクリップボードから画像を貼り付けられるようにする

「クリップボードの画像ファイルをアップロードする」
http://qiita.com/volpe28v@github/items/dc100c75c2371bb82a3b

という記事を参考にしました。

結果として、

  1. クリップボード内の画像データをページに添付して、
  2. 添付ファイルへのリンクを張る、

という一連の動作を自動化できました。

これまでであれば、

  1. クリップボード内の画像データをファイルとしてPCに保存する
  2. 保存したファイルをページに添付する
  3. 添付したファイルへのリンクをソースに埋め込む
  4. PC上に残った保存したファイルを消す

という作業が必要だったのと比べると作業効率が大きく向上します。

スクリーンキャプチャーを多数張り込むようなページを書くのにとても重宝しそうです。

制限

今のところ Chrome でしか動作確認が取れていません。

Firefox などは最新の Clipboard API に対応していないそうです。

使い方

ソースコード編集画面は見た目上、何も変りません。

  編集画面.png

クリップボードに画像がある状態で、右クリックから「貼り付け」を選択するか、 Ctrl+v を押すと、ファイル名を聞くダイアログが表示されます。 ダイアログで Cancel を押せば貼り付けはされません。

  ダイアログ.png

ダイアログに入力した名前で画像がアップロードされ、 アップロードされた画像へのリンクが貼り付けた位置に挿入されます。

  リンク.png

画像として表示するには、拡張子を .png としておく必要があるようです。

処理の基本的な流れ

  1. ソース編集用の textarea の paste イベントを拾う
  2. clipboardData.items から画像データを探す
  3. getAsFile() でデータを取り出す
  4. window.prompt でファイル名の入力を促す
  5. new FormData() で attach プラグインに渡すフォームデータを作成する
  6. jQuery.ajax でフォームデータを post する

ソースファイル

lib/html.php の edit_form 関数の中で $body = <<<EOD を探し、 対応する EOD の直前に以下のコードを貼り付けます。

LANGUAGE: html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.js"></script>
<script>

// from http://qiita.com/volpe28v@github/items/dc100c75c2371bb82a3b
$("textarea[name='msg']").on('paste', function(event){
  // event からクリップボードのアイテムを取り出す
  var items = (event.clipboardData || event.originalEvent.clipboardData).items; // ここがミソ
  for (var i = 0 ; i < items.length ; i++) {
    var item = items[i];
    if (item.type.indexOf("image") != -1) {
      // 画像データがあればページに添付する
      var image = item.getAsFile();
      upload_file_with_ajax(image);
    }
  }
});

// ファイルアップロード
function upload_file_with_ajax(file){
    var img_name = window.prompt("Image file name", "noname.png");
    if(img_name==null) return;

    var formData = new FormData();

    // from http://hakuhin.jp/js/form_data.html#FORM_DATA_02
    formData.append("attach_file", file, img_name);
    formData.append("encode_hint", "ぷ");
    formData.append("plugin", "attach");
    formData.append("pcmd", "post");
    formData.append("refer", "$s_page");

    $.ajax('$script' , {
      type: 'POST',
      contentType: false,
      processData: false,
      data: formData,
      error: function() {
        // アップロードエラー処理
        beep();
      },
      success: function(res) {
        insertAtCaret($("textarea[name='msg']"),
          "&ref("+img_name+");");
      }
    });
}

// textarea の選択位置に文字列を挿入する
// from http://d.hatena.ne.jp/spitfire_tree/20131209/1386575758
function insertAtCaret(target, str) {
  var obj = $(target);
  obj.focus();
  if(navigator.userAgent.match(/MSIE/)) {
    var r = document.selection.createRange();
    r.text = str;
    r.select();
  } else {
    var s = obj.val();
    var p = obj.get(0).selectionStart;
    var np = p + str.length;
    obj.val(s.substr(0, p) + str + s.substr(p));
    obj.get(0).setSelectionRange(np, np);
  }
}

// ビープ音を鳴らす
// from http://qiita.com/isseium/items/12b215b6eab26acd2afe
function beep()
{
  new Audio(
    "data:audio/wav;base64,"+
    "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"+
    "U291bmQgRm9yZ2UgNC41AA==").play();
}

</script>

質問・コメント





Counter: 8998 (from 2010/06/03), today: 5, yesterday: 0