はじめてのブックマークレット

ふだんはEmacs＋Org-babelでPerlおよびElispを書いているが、今日ブラウザーでちょっとした便利なことをするためにJavaScriptとブックマークレットに挑戦した。
（JavaScriptは知ってたつもりだけど、もう忘れてる……）

# やりたかったこと
- ある規則に沿った文字列をマウスで選択する
- ブックマークレットを起動すると、選択した文字列のある部分文字列が置換されてクリップボードに入る

# 副次的に出来るようになったこと
- EmacsでJavaScriptを編集する
- org-babelで実行する
- ブックマークレットを書く
- 実行、デバッグする

# Emacs／Org-Mode／BabelでJavaScriptを起動できるようにする
> ※コンソール上で動作するJSプログラムを書いても、Bookmarkletはまた話が違うので、あまり意味がなかった。。

***環境：*** Windows 10 Pro＋WSL＋Ubuntu
***参考：*** http://misohena.jp/blog/2017-10-26-how-to-use-code-block-of-emacs-org-mode.html#orge501ae7）

## コンソールからnodeをセットアップする
```console
$ sudo apt install node # node.jsをインストールする
$ which js # jsコマンドの存在を確認する
```

## init.elでOrg-mode／Babelにjsを追加する
```.emacs.d/init.el
;;; 実際にはOrg-Modeで管理している
(eval-after-load "org" '(org-babel-do-load-languages 'org-babel-load-languages '(…既存の言語の定義…(js . t))))
(setq org-babel-js-cmd "js")
```
## JavaScriptでHello World
適当なorgファイルの`#+BEGIN_SRC～#+END_SRC`の間にソースを書き、カーソルを中に入れて`C-cC-c`で実行結果が`#+RESULTS`に出る

```foo.org
#+BEGIN_SRC js :exports both
console.log("Hello, World!");
#+END_SRC

#+RESULTS:
: Hello, World!
: undefined
```

## ブックマークレットを作る
***参考：*** https://hirata.blog/201710_lets-bookmarklet/

```
#+BEGIN_SRC js :exports both
  javascript:!function(undefined) {
      alert('Hello World Two!')
  }();
#+END_SRC
```

- 先頭にjavascript:と書く
- 他のJSコードに影響を与えないために無名関数で作る必要がある
- http://dean.edwards.name/packer/ で空白、改行を除いて圧縮する
- Chromeで、ブックマークのURLに圧縮したコードを入れ、適当な名前でブックマークする
- ブックマークを呼び出すと「Hello World Two!」という文字列がダイアログ表示される

## クリップボードに特定の文字列を入れるブックマークレット
```js
#+BEGIN_SRC js :exports both
javascript:!function(undefined){
    // 任意の処理を記述
    !function(a){
        var b = document.createElement('textarea'),
        c = document.getSelection();
        b.textContent = a, document.body.appendChild(b), c.removeAllRanges(), b.select(), document.execCommand('copy'), c.removeAllRanges(), document.body.removeChild(b);
    }('ここにコピーしたい文字列を記述する');
}();
#+END_SRC
```
- 実行すると「ここにコピーしたい文字列を記述する」という文字列がクリップボードに入る。ﾍﾞﾝﾘﾀﾞﾅｰ

## 特定の文字列を置換するJavaScript
```js
#+BEGIN_SRC js :exports both
var text = "Hello, World!";
text = text.replace('Hello', 'Goodbye');
console.log(text);
#+END_SRC

#+RESULTS:
: Goodbye, World!
: undefined
```

- replace関数で文字列を置換する

## クリップボードに入れる字を置換するブックマークレット
```js
#+BEGIN_SRC js :exports both
javascript:!function(undefined){
    var text = "Hello, World!";
    text = text.replace('World', 'Folks');
    !function(a){
        var b = document.createElement('textarea'),
        c = document.getSelection();
        b.textContent = a, document.body.appendChild(b), c.removeAllRanges(), b.select(), document.execCommand('copy'), c.removeAllRanges(), document.body.removeChild(b);
    }(text);
}();
#+END_SRC
```

- ブックマークレットとして実行されると「Hello, Folks!」とクリップボードに入る。ﾂｸﾂﾞｸﾍﾞﾝﾘﾀﾞﾅｰ

## マウス選択した文字列を取得する
***参考：*** https://stabucky.com/wp/archives/1702

```js
#+BEGIN_SRC js :exports both
javascript:!function(undefined){
  var x=document, y=window, t;
  if(x.selection){
    t=x.selection.createRange().text;
  }else if(y.getSelection){
    t=y.getSelection();
  }else if(x.getSelection){
    t=x.getSelection();
  }
  alert(t);
}();
#+END_SRC
```

- マウスで文字列を選択してからブックマークレットを実行すると、選択した文字列がダイアログ表示される。ﾓｳｽｸﾞﾀﾞ｡｡

## 選択した文字列を置換してクリップボードに入れる
```js
#+BEGIN_SRC js :exports both
  javascript:!function(undefined) {
      var x = document,
          y = window,
          t;
      if(x.selection) {
          t=x.selection.createRange().text;
      } else if(y.getSelection){
          t=y.getSelection();
      } else if(x.getSelection){
          t=x.getSelection();
      }
      t = t.toString().replace('置換前の文字列', '置換後の文字列');
      !function(a){
          var b = document.createElement('textarea'),
              c = document.getSelection();
          b.textContent = a,
          document.body.appendChild(b),
          c.removeAllRanges(),
          b.select(),
          document.execCommand('copy'),
          c.removeAllRanges(),
          document.body.removeChild(b);
      }(t);
  }();

#+END_SRC
```

## ハマったこと、デバッグ方法
- tは文字列だと思っていて直接t.replace()していた
- Chromeのインスペクターウィンドウ（Ctrl＋Alt＋I）で見ると、t.replace()なんて関数アリマセンと怒られていた
- エラーメッセージで検索すると外国のStackOverFlowに当たり、toStringを噛ますように言われた

## 今後の課題
- プログラムをEmacsからコピペし、packerで圧縮してコピペし、ブックマークを編集するのがメンドクサイ
- プログラムを書いたら改行、空白を取ってクリップボードに入れるところまではElispで簡単に出来るだろう
- それをブックマークに入れるところもがんばれば出来るかも？

いろいろ楽しいことができそうだ。

***（この項終わり）***