トップ 最新 追記

2016-01-11 [長年日記]

_ window.postMessageを使ってiframeの中のリンクを外のwindowで遷移させる

まとめ

やりたいこと

iframe の中のリンクをクリックしたら元 window で遷移してほしい。

できた

前提としては 元 window の JavaScript も iframe 内の JavaScript も自由にいじれること。

  1. 元 window で iframe の load が終わったら iframe の window に対して postMessage で自分の origin を伝える
  2. iframe 内の window で click を拾って url を window.parent.postMessage で元 window に送る
  3. 元 window は送られた url を location にぶちこむ

できた!

分かったこと

  • そもそも iframe って許可されていないとコンテンツの表示もできなくなってた
    • X-Frame-Options とか最近はセキュリティ関係のヘッダいろいろあるんだね
    • Sinatra はデフォルトセキュア寄りなので何も表示されずに悩んだ
  • window オブジェクトとか普段触らないのでアクセス方法分からなくなる
  • postMessage って自由に送れるのかと思ったら送信先の origin をちゃんと送る側が分かってないとダメ
  • iframe の src まんまみたいなもんじゃんと思ったけど、逆方向の時には工夫が必要
  • window.postMessage では object は送れない。より複雑な双方向のやりとりをするには JSON.stringify などを使ってデータ構造を持たせないと厳しそう。

やったこと

ざっくり以下のような感じ。

parent window

<!-- iframe を作る -->
<iframe name="widget" src="http://example.jp"></iframe>

<script type="text/javascript">

/** iframeのコンテンツを読み込み終わったらparentの何か送る(なんでもよい) */
document.getElementsByName('widget')[0].addEventListener('load', function(e) {
  window.frames.widget.postMessage('loaded', 'http://example.jp');
});

/** iframe内のクリックされたurlが送られてくるのでlocationを書き換える */
window.addEventListener('message', function(e) {
  if ( e.data ) {
    location = e.data
  }
}, false);

</script>

iframe の中(http://example.jp)で jQuery を使ったとする。

/** parent windowのoriginを保存 */
window.addEventListener('message', function(e) {
  widget.target = e.origin;
});

/** リンクをクリックしたらparent windowに教える */
$('a').on('click', function(e) {
  window.parent.postMessage($(e.target).attr('href'), widget.target);
});

工夫したところ、悩んだところ

iframe 内の window では parent の origin が分からないのでそのままでは postMessage の際に origin を指定できない。そこで parent 側で iframe の内容の load イベントを待って parent の情報を送ってやる。

iframe の event を拾うには iframe 要素を、iframe 内に message を送るには window オブジェクトを、使い分ける必要があってなんかメンドイ。

参考

Tags: JavaScript

2016-01-29 [長年日記]

_ WindowsのRubyでGitのcommitを扱おうとしてた

一言で言うと cmd.exe 上で動かすと外部コマンドからの入力を Windows-31J だと思い込んでしまうので .force_encoding('UTF-8') を足せという話だったっぽい。(実際には日本語の部分は捨てていたのでなんでもよかった。)

要はこんなやつです。

`git log -n 1 --oneline master`

こいつの結果を処理しようとしてたんだけど、OSX だとうまく動くのに、Windows だと

invalid byte sequence in Windows-31J

って言われちゃう。

Git の commit log って UTF-8 決め打ちじゃないんだっけ、と思いながら Windows の Ruby は Windows での利用に都合のいいように外の世界は Windows-31J で動いているのだという設定になってるんじゃないかな。

ということで

`git log -n 1 --oneline master`.force_encoding('UTF-8')

しておしまい。最終的には hash が手に入ればよかったので、調べたら

`git log -n 1 --pretty=%h master`

でもよかったかもしんない。git ってたまに help 読むとあーなるほどと思うことしきり。(奥が深い症候群か)