メッセージ欄

2010年6月の日記

一覧で表示する

iframe内でGreasemonkeyを実行させない方法
2010/06/16(水) 15:47 Greasemonkeyはてブ情報 はてブに登録 はてブ数

Greasemonkeyで@includeをhttp://*など広い範囲に指定しているとき、実行されるページにインラインフレーム(iframe)があると、そのiframe内でもGreasemonkeyスクリプトは実行されるのでややこしい事があります。

例えば、iframe pageのページにはiframeが2つあるので、下のようなスクリプトだと3回もlogが表示されるためiframeの存在に気づかないとスクリプトがバグってるのかと誤解します。
// ==UserScript==
// @name           iframe test
// @namespace      http://efcl.info/
// @include        http://*
// ==/UserScript==
GM_log("テスト");
GM_log(location.href); // URLを表示すると意味が分かりやすい。
そのため、iframe内では実行させないようにすると、無駄な気遣いが減って(無駄なスクリプトの実行も)スクリプトの開発が楽になります。
以下がiframe内ではGreasemonkeyスクリプトを実行させない対処を入れたものです。
// ==UserScript==
// @name           iframe test
// @namespace      http://efcl.info/
// @include        http://*
// ==/UserScript==
new function(){
    // iframe内では実行させない
    if (window != unsafeWindow.top) {
        return;
    }
    GM_log("テスト");
    GM_log(location.href);
}()
iframeがクロスドメインのものだとwindow.topでは何か(Security Manager vetoed action)言われるのでunsafeWindowを使っています。
わざわざ無名関数で全体を囲っているのはGreasemonkey スクリプト全体を無名関数で囲う意味でも説明しましたが、いきなりreturnをする事があるのでそうしています。(ただし@unwrapを付けてない場合はあんまり関係ない)
このスクリプトだとiframe pageでGreasemonkeyを実行しても一回だけの表示になると思います。
murky-satyr によるとtry...catchでつぶしてしまった方がunsafeWindowを使わずに済むので安全だそうです。
    try { if(top !== self) throw 0 }catch([]){ return }// iframe内ならreturn
    GM_log("テスト");
iframe内でGreasemonkeyが実行されて困るのはWordpressやDinkypageなどのリッチエディタを使用しているページでGreasemonkeyが勝手に要素を加えるとエディタ内にそれが入ってしまうという問題があるため、必要なもの以外はiframe内で実行させない方がいいです。

Greasemonkeyスクリプト全体を無名関数で囲う意味
2010/06/06(日) 22:43 Greasemonkeyはてブ情報 はてブに登録 はてブ数

よくGreasemonkeyスクリプトを見ると全体を無名関数(匿名関数)で囲っているものを見ることがあると思います。
(function(){
    // 処理内容
})();
何でこのような記述をしているかというと、歴史を掘り返すのは面倒なので簡潔に
  1. 昔はトップレベルに宣言した変数が外部に影響を出してしまっていた?
  2. 今はevalInSandboxで実行されているので無名関数で囲わなくても問題はない。
(この無名関数自体がどういう動作をするかはfunction についてを読むといい)
つまり、今は囲まなくても問題はない。(ただしGreasemonkeyに限る)

でも、実際のスクリプトでは囲んでいる場合が多いと思うのでどうしてかというと以下のような理由がある。
  • 習慣的に囲う
  • .user.jsというユーザースクリプトはGreasemonkey以外でも動かす可能性があるので、他のブラウザを考慮して(Operaとか)
他のブラウザだと、グローバル汚染になってしまうことがあるので無名関数で囲っておくと少し優しいよ。
ユーザスクリプトを (function() ...)(); で囲むことについて - mallowlabsの備忘録
  • いきなりreturnできる
無名関数で囲っておけば、以下のようなコードも問題ない。
(function(){
    return;
})();
Greasemonkeyとして実行されるScriptには前に"(function()\n"が、後ろに"\n)()"が付加されて実行されるという動作になっているので、本来は上のように自主的に囲うことなくてもreturnはできるが、Greasemonkeyは(function()\nと\n)()を付加しなくなる(という夢を見た) - FFFF - 0xのようにいきなりその仕様が無くなることがあり得るので、returnしたい人は自主的に囲っておく方がよい。
ただ2010年6月6日現在のソースを見るとデフォルトではまた無名関数で囲んでから実行されている気がするけど、念のため囲っておいた方がいいじゃないかな。
components/greasemonkey.js at master from greasemonkey's greasemonkey - GitHub
現在は囲わなくてもreturnできるけど、未来に変化があるかもしれないので念のためって事。
また、このGreasemonkey側でスクリプトの前後を囲うか否かは@unwrapというメタ情報によって決めることができる。
以下のように@unwrapを入れると、無名関数で囲わずに実行されるようになっている。
// ==UserScript==
// @name Filename
// @namespace http://efcl.info/
// @description 説明文
// @author azu
// @homepage http://efcl.info/
// @unwrap
// ==/UserScript==
@unwrapありなしの動作は以下も参考にGM_listValues, GM_deleteValue, @unwrap - 枕を欹てて聴く
  • エイリアスを自然に作れる
amachang の 「一行で IE の JavaScript を高速化する方法」を掘り下げてみた - latest logでも出てくる話だけど、ただ無名関数で囲んで実行するだけだと寂しいから、エイリアスなどを作るといいかもね。
function について
(function(_doc) {
    console.log(_doc);    // document
})(document);
new function(_doc) {
    console.log(_doc);    // document
}(document)
結論的には囲わなくても良いけど、囲った方が無難だと思う。
  • [greasemonkey]Greasemonkeyスクリプトの開発で役に立ったサイトや本 Alone Like a Rhinoceros Horn
    Firefox にこんな機能があればいいなあ → ん、Greasemonkey というのでできるらしいぞ → ユーザースクリプトとやらを書けばいいのか → どうやって書くんだ? というところからスタートして、最終的に自作のユーザースクリプトを公開するに至...

ファイルの編集とエディタ
2010/06/05(土) 23:51 Greasemonkeyはてブ情報 はてブに登録 はてブ数

Greasemonkeyスクリプトの編集方法について。
初めてGreasemonkeyの新規スクリプトの作成したときにエディタのパスを指定するダイアログが出るが、なぜかGreasemonkeyの管理画面にエディタを決めるところが存在しない。
エディタパスの再設定をするときはロケーションバーにabout:configと入れ、greasemonkey.editorに使いたいエディタのパスを入力する。
Greasemonkey のスクリプト編集時に使うエディタを変更する - present

スクリプトの編集方法

sshot-2010-06-05-1.png
  1. Greasemonkeyアイコン右クリック
  2. ユーザースクリプトの管理をクリック
  3. 対象のグリモンスクリプトを選択
  4. 編集ボタンクリック
でエディタを開けるがこれはとても面倒となるので、通常はGreasemonkeyを右クリック→スクリプト名を右クリックすることでスクリプトをエディタで開くことができる。
グリモンをエディタで開く最短の方法を知った - SO NOTE そうのて (;^ω^)

GreasemonkeyスクリプトファイルのエンコードはSJISでも動くが、日本語などを表示したい場合はファイルのエンコードをUTF-8にしてから編集した方が良い。
Greasemonkeyで\u65e5\u672c\u8a9eのような文字列を見ることがあるが、これはユニコードエスケープした文字列である。(エスケープツールは>>こちら<<)
しかし、GreasemonkeyはUTF-8のファイル内なら日本語を直接書けるので、日本語をそのまま書くようにした方がいい。

おまけ:
新規スクリプトの作成でも述べたが、エディタでそのスクリプトのメタ情報を書き換えても反映しないが、ユーザースクリプトの管理からメタ情報のincludeなどを書き換えたときは反映する。
これはユーザースクリプトの管理から編集を行うと %profile%\gm_scripts\config.xml に直接メタ情報を書き込んでいるからである。

新規スクリプトの作成
2010/06/05(土) 23:32 Greasemonkeyはてブ情報 はてブに登録 はてブ数

まずはスクリプトの作成方法からメタ情報の話まで。
Greasemonkeyで新しくスクリプトの作り方は2つ方法がある
  1. 新規ユーザスクリプトのダイアログから作る
  2. .user.jsのファイルを作りFirefoxにD&Dしてインストールする
ダイアログから作成の手順を見ていく。
ステータスバーのGreaseMonkeyアイコンを右クリックして、新規ユーザスクリプトを選択。
ダイアログのそれぞれの項目についてはGreaseMonkeyスクリプト作成クイックスタート - mitc - 日記を読むといいでしょう。
  • @name Greasemonkeyの区別に使われる名前です。
  • @Namespace 同じく区別に使われるので、ドメインなどを入れておくのが定番
  • @Description 説明文。Userscripts.orgに置くときとかは書いてあると勝手に読み取ってくれる。
  • @includes 動作するURL。正規表現は使えないが、*が使え何に対しても最短一致する。
普通のWebページ全部で動かすなら以下のように書く。
http://*
https://*
最長一致でした。content/convert2RegExp.js at master from greasemonkey's greasemonkey - GitHub
正規表現的なマッチは*(アスタリスク)以外使えないので、もっと詳細なマッチをしたい場合はスクリプト内で判別するようにする。
*(アスタリスク)は最短一致なので、正規表現とは違い、
http://efcl.info/*/fuga?* と書いたとき、
http://efcl.info/hoge/fuga? にはマッチし、
http://efcl.info/hoge/foo/fuga? にはマッチしない。
また、Greasemonkey0.82からはローカルでの動作はデフォルトではOFFになったため、file:///*のような指定しただけでは動作しないことに注意。
about:configのgreasemonkey.fileIsGreaseableをtrueにする必要がある。
Greasemonkey ver 0.82解説 - 枕を欹てて聴く
  • @excludes 動作しないURLを指定する。基本的にincludesと同じなので省略
また@includes、@excludesにはMagic TLDというものが存在し、ドメイン部分に.tldを使うとあらかじめ用意されたドメインっぽい文字列とマッチする。
よく見かけられる例が@includesにhttp://www.google.tld/* という指定がある場合にはtld部分がcomやco.jpなどGreasemonkeyであらかじめ用意されたドメイン文字列とマッチする。(あんまり信用しすぎないように)
詳しくはMagic TLD - greasemonkey - GitHubを読む。

これでダイアログにあるメタ情報については説明終了。
他にもメタ情報は存在するので、詳しくはGreasemonkey Manual - Metadata Block - greasemonkey - GitHubを読む。
他にあるメタ上で使われるものとして、ライブラリなどを外部URLから読み込める@requireと同じく外部からリソース(画像やCSS)を読み込む@importは使われることが多い。
ここで注意することはスクリプトにもメタ情報は書いただけではメタ情報は更新されない事。
インストールし直すことでメタ情報の更新が行われれる(@requireや@importはインストールしたタイミングでダウンロードされる)

結局どんなメタ情報を入れておけばいいかというと、自分は以下のような感じにしている。
@homepageはUserscripts.org用な感じがする。定型文でも作っておくと楽です。
// ==UserScript==
// @name Filename
// @namespace http://efcl.info/
// @description 説明文
// @author azu
// @homepage http://efcl.info/
// ==/UserScript==

1: satyr 『> *(アスタリスク)は最短一致なので、正規表現とは違い、 .* に置き換えるので最長一致のはず。 [re = conver...』 (2010/06/06 7:03)

2: Generic Cialis 『Thank you for sharing to us.there are many person searching abou...』 (2011/05/21 16:53)

Greasemonkey入門
2010/06/05(土) 22:54 Greasemonkeyはてブ情報 はてブに登録 はてブ数

Greasemonkeyスクリプトの開発について書いていく。
書いていく上でのハマりどころやTipsなど。
GreasemonkeyとXPCNativeWrapperの話。