Bookmarklet / Javascript / Kotlin/JS

## 目的
ブラウザから非CORSなWebサービスを使うために、Bookmarkletで本来のページに寄生する。
(将来の自分に向けたメモ)

## 環境
OS: Windows
Browser: Chrome 97

## 基礎
Webブラウザのブックマークのリンクに`javascript:`に続けてjavascriptの実行コードを記載。
アドレスバーに入れてもOK。ただしコピペすると"javascript:"が消えるのでそこだけ手入力。

```javascript:例:AlertダイアログでHelloを表示
javascript:alert("Hello");
```
```javascript:例:HTMLを編集可に
javascript:var a=document.getElementsByTagName("body")[0];a.setAttribute("contentEditable","true"!=a.getAttribute("contentEditable"));
```

## コード長の制限
alert("12345678901234...長い文字列...")で試行。10000文字までは問題なし。

Bookmarklet特有の話題は以上。

## 文法チェックと圧縮 - [Google Closure Compiler](https://closure-compiler.appspot.com/home)
以下、サンプルコードはこれを使ってコンパイルしてます。

## 遅延実行 [window.Function()を使えとのこと](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/eval#eval_%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E3%81%A7%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84!)

```javascript
(()=>{
  window.Function('"use strict";return (alert("'+window.location+'"))')();
})();
```
上はalert表示するコードを生成し、それを評価(実行)する関数を、評価する。

## 外部リソースを取り込む [fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch)

どこかのWebサーバ上に[jsファイル](https://kyoya-p.github.io/samples/2022/Bookmarklet/alert-test.js)を用意してそれを取り込む。

```javascript
fetch('https://kyoya-p.github.io/samples/2022/Bookmarklet/alert-test.js') //要求Promiseを生成
  .then(res=>res.text()) //要求Promiseを待ち、応答Promiseを生成
  .then(data=>alert(data)) //応答Promiseを待ち、結果表示Promiseを生成
```

※githubはCORS対応がされていて外部サイトからの参照が楽で助かる
※と思いきや[CSP](https://github.blog/2013-04-19-content-security-policy/)に阻害されるページも...
[W3C CSP Level3 Draft](https://triple-underscore.github.io/CSP3-ja.html)

ともかく以降いちいちブラウザのBookmarkを書き換える必要は無くなった

```javascript
fetch('https://kyoya-p.github.io/samples/2022/Bookmarklet/alert-test.js')
  .then(res=>res.text()) 
  .then(jssrc=>window.Function('"use strict";return('+jssrc+')')())
```

上記をBoolmarkletに変換。これをブラウザのBookmarkのURLに設定。

```javascript
javascript:(()=>{fetch("https://kyoya-p.github.io/samples/2022/Bookmarklet/alert-test.js").then(function(a){return a.text()}).then(function(a){return window.Function(a)()});})()
```

目的のページを開いてからBookmarkを選択。


以下おまけ


## Kotlin/JSで本体を作成 - [IntelliJ](https://www.jetbrains.com/ja-jp/idea/)でプロジェクト作成

ファイル > 新規 > プロジェクト - 新規プロジェクトダイアログが開く
Kotlin > Browser Application を選択し次へ [JS IR compiler]を選択

例えばプロジェクト名を"WebSED"とすると関数はこの名前のオブジェクトのメンバとして実装される。

## [JavaScriptからKotlinを呼び出すテスト](https://kotlinlang.org/docs/js-to-kotlin-interop.html)

[コード追加:](https://github.com/kyoya-p/samples/blob/02066b1ac5717041a6d74939f40a286dca7a646c/2022/WebSED/src/main/kotlin/Client.kt#L19-L23)

```kotlin
@ExperimentalJsExport
@JsExport
fun hello() {
    document.body?.sayHello()
}
```

- 関数に `@JsExport`を付与する
- JSのモジュールシステムは Plainモード(指定なし)

確認:
1. `gradlew browserRun` でブラウザを起動。"Hello from JS"が表示されていることが確認できる(これはプロジェクトのスケルトンコードによるもの)
2. Bookmarkletとして`javascript:WebSED.hello()` を設定し実行。"Hello from JS"がもう一行表示されればOK(開発者コンソールでやってももちろんOK)

#Kotlinで生成したjs関数をBookmarkletに
Kotlinからトランスパイルされた下記をWebに置く

- `build/distributions/WebSED.js`
- `build/distributions/WebSED.js.map`

## 関連ソース
- https://github.com/kyoya-p/samples/tree/master/2022/Bookmarklet
- https://github.com/kyoya-p/samples/tree/master/2022/KotlinJs2022
- https://github.com/kyoya-p/samples/tree/master/2022/RXWeb