1月
29
2010
2

Chrome 正式版 Greasemonkey でクロスドメイン POST をする方法

最近公開された、Google Chrome の Ver 4 では、正式に Greasemonkey がサポートされ、以前のように特別なオプションを指定することなく、ワンクリックでユーザスクリプトがインストール出来るようになりました。
それ自体は非常に嬉しい事だったんですが、バージョンアップに伴い、はてブ with Twitter が動かなくなってしまっていました。(現在は修正済み)

以前、JavaScript だけでクロスドメインで POST メソッドを送る方法で紹介したやり方が、Chrome のバージョンアップによって無効になってしまったためです。
無効になったとはいえ、通常の JavaScript として使用する分には問題なく、Greasemonkey だけに問題が発生していました。
動的に生成した iframe の contentWidow オブジェクトが取得出来なくなっており、セキュリティの制限が強化されたものと思われます。

最終的にはその制限を回避する方法を見つけたので、以下に解説します。

通常 JavaScript の記述

まず、Greasemonkey ではなく普通の JavaScript としてJavaScript だけでクロスドメインで POST メソッドを送る方法等を参考に、本来やりたい処理を記述します。
この時は普通に script タグでスクリプトを読み込んで、正常動作を確認しておきます。

そして、正常に動作するスクリプトが作成出来たら、それを任意のサーバにアップします。

Greasemonkey の記述

以下のようなスクリプトを書きます。

(function() {
    var d = document;
    var s = d.createElement('script');
    s.src = 'http://www ...'; // スクリプトファイルをアップした場所
    d.body.appendChild(s);
})();

これだけで、本来の window オブジェクトから実行したかった処理が実行され、Greasemonkey の制限に掛かることなく、iframe を使用したクロスドメイン POST が実現します。

でもちょっと待って

Greasemonkey が実行されるたびに、自分のサーバから js ファイルがダウンロードされるなんて嫌ですよね?私は嫌です。レスポンスを考えたって好ましくないですし。

そこで、data スキームを使って外部スクリプト自体を Greasemonkey スクリプトの中に埋め込んでしまう事にします。(data スキームについてはこの辺を参照して下さい。)

data スキームへの変換には、[JavaScript] dataスキームURI生成(画像データのBase64変換)を使用させていただきました。
このサイトで、先ほどアップした js ファイルの URL を指定し、data スキームに変換した文字列を取得します。

その上で、Greasemonkey を以下のように書き換えます。

(function() {
    var data = 'data:application/x-javascript;base64,'+
        'KGZ1bmN0aW9uKCkgewoJdmFyIGQgPSBkb2N1bWVudDsKCWZ1bmN0aW9uIGdldEVsZW1lbnQoeHBh'+
        // 中略
        'fSkoKTs=';
        var d = document;
    var s = d.createElement('script');
    s.src = data;
    d.body.appendChild(s);
})();

これで、単体の Greasemonkey スクリプトでありながら、外部スクリプトを読み込んだのと同等の状況を作り出す事が出来ます。

これでスッキリしましたね!

Written by Otchy in: Development | タグ: , , ,
11月
04
2009
3

Greasemonkey で 超お手軽に jQuery を使うスニペット

タイトルの通りです。

特徴

  • script タグ追加型の読み込み
  • $ 関数として利用可能
  • 該当ページですでに jQuery が読み込まれていればそれを利用
  • jQuery スクリプト自体のアップは不要 (Gogole の CDN を利用)
  • ローカルのキャッシュも多分有効 (CDN が適切なヘッダを返してれば)
  • jQuery 読み込み完了を待ってから実行される

作成動機

Greasemonkey で jQuery を使う方法検索してみると、GM_xmlhttpRequest で読み込んで eval する方法と、script タグを追加する方法に大別されます。
前者の方がスマートなやり方ではあるのですが、スニペットとして貼り付けるにはいかんせんコードが長くなりがちなのと、jQuery が導入される名前空間の違いからか、jQuery がフル機能で利用出来ないといった制限があるようです。
そこで後者を選択しようと思ったのですが、検索で上位に来るスクリプトはいまいち洗練されていなくて、二重読み込みなどの問題が解決されていなかったりします。

で、自分で書く事にしました。
特に任意のサイトで動作させるスクリプトを書くような場合、元々のページに jQuery が導入済みでもそれに干渉しない、というのがウリでしょうか。

スクリプト

(function(d, func) {
    var check = function() {
        if (typeof unsafeWindow.jQuery == 'undefined') return false;
        func(unsafeWindow.jQuery); return true;
    }
    if (check()) return;
    var s = d.createElement('script');
    s.type = 'text/javascript';
    s.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js';
    d.getElementsByTagName('head')[0].appendChild(s);
    (function() {
        if (check()) return;
        setTimeout(arguments.callee, 100);
    })();
})(document, function($) {
    // ここにメインの処理を書く
    $('#button').click(function(){
        alert('clicked!');
    });
});

重たい処理は必要ないぞ、っていう場合はこちらも参考にどうぞ。
Greasemonkey スクリプトの冒頭に書く 5 行

Greasemonkey を書く時に頻繁に利用する関数をまとめたので、公開してみます。
外部の JavaScript ライブラリを読み込む方法を解説したサイトもありますが、そこまで大げさな機能が必要でもなく、軽く動作させたいときに便利です。
特に共通ライブラリを利用すると、Firefox 以外のブラウザの対応も無駄に読み込む事になるので、スマートじゃないなぁと思います。

Written by Otchy in: Development | タグ: , ,
6月
04
2009
2

Twitter 上のどせいさんの素敵なお言葉をいつものフォントで表示するグリモン

今日 RT で Twitter 上にどせいさんがいる事が判明したので、さっそくグリモンを書いてみました。

ごちゃごちゃ難しい事は言いません。
下のスクリーンショットを見て下さい。

どせいさん

インストールはこちらから。どせいさん on Twitter

Written by Otchy in: Development | タグ: ,
2月
10
2009
2

ゲームメーター with Twitter 作ったよ

昨日から巷で大人気のゲームメーターですが、ゲームメーター内の機能で「つぶやき」というのがあります。
まあ、まんま Twitter みたいなもんで、設定次第で Twitter への同時ポストも可能なのですが、Twitter へ同時ポストするためには、ゲームメーターにパスワードを預けないといけません。

個人運営のサービスに対して、さすがにちょっと心配よね、などと思ったので、グリモン書いておきました。

ゲームメーター with Twitter

Written by Otchy in: Development | タグ: , ,
1月
20
2009
3

Greasemonkey スクリプトの冒頭に書く 5 行

WordPress with Twitter の不具合を修正した記念に、Greasemonkey を書く時に頻繁に利用する関数をまとめたので、公開してみます。
外部の JavaScript ライブラリを読み込む方法を解説したサイトもありますが、そこまで大げさな機能が必要でもなく、軽く動作させたいときに便利です。
特に共通ライブラリを利用すると、Firefox 以外のブラウザの対応も無駄に読み込む事になるので、スマートじゃないなぁと思います。

var d = document;
var $ = function(id) { return d.getElementById(id); }
var $x = function(xp) { return d.evaluate(xp, d, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; }
var $a = function(xp) { var r = d.evaluate(xp, d, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); var a=[]; for(var i=0; i<r.snapshotLength; i++){ a.push(r.snapshotItem(i)); } return a; }
var $e = function(e,t,f) { if (!e) return; e.addEventListener(t, f, false); }
  • d
    document のエイリアスです。目的はコードの短縮と実行速度の高速化です。
  • $ 関数
    getElementById のエイリアスです。説明不要でしょう。
  • $x 関数
    xpath を引数としてとり、最初に一致したエレメントを返します。
  • $a 関数
    xpath を引数としてとり、一致したエレメント全てを配列で返します。
  • $e 関数
    addEventListener のエイリアスです。説明不要でしょう。

Greasemonkey で既存のサイトをいじくる場合、対象のエレメントに必ずしも id が振られているとは限らない (むしろそうなっていない場合が多い) ので、xpath から任意のエレメントを簡単に取得できる、$x/$a は有用かなと思います。
この辺は、ブラウザ間の互換を考えないといけない汎用ライブラリではなかなか実装できないところですね。

もちろん、下記のように名前空間を汚さないように書くのは基本的なマナーです。
$ 関数とかをグローバル (window オブジェクトのメンバ) に定義しちゃうと、サイトによっては壊滅的に動作がおかしくなってしまうかも?

(function(){
    // 処理本体
})();

2009-01-26 追記 — コメントでご指摘いただいた点について

Greasemonkey の実行環境はサンドボックス上にあるので、function によるラッピングは不要だそうです。
ちまたでよく見る GM は大概ラッピングされていたので、ずっと勘違いしていました。公式マニュアルにリンクしておきます。
公式マニュアル

$a のパフォーマンスが良くないという話もありますが、配列のサイズがあらかじめ確定しているので、配列のインスタンス生成時にサイズを指定するようにして、push を使わないほうがいいよ。って事かと思います。気になる方は直して使って下さい。

いずれにせよ、ご指摘ありがとうございました。

Written by Otchy in: Development | タグ: , , ,

Powered by WordPress | Aeros Theme | TheBuckmaker.com