2010-12-23
GoogleChromeやOperaでもGM_*Value(s)系関数を使えるようにする
JavaScript, Greasemonkey | |
![]()
Firefox向けのuserJS書いていたんですが、GoogleChrome, Operaにも対応させたくなったので、以下のサイト様を参考にGM_*Value(s)系の関数が実装されていないときにoverrideする処理書きました。
参考元サイトさま。
GM_setValue系をChromeでも使えるようにする - Firefoxアドオンとか
ソース
/** * 各関数が実装されていない場合、localStorageで代用する */ function GM_XBrowse() { var gmFuncs = {}; // functions ---- gmFuncs.GM_setValue = function (key,value) { return localStorage.setItem(key, value); }; gmFuncs.GM_getValue = function (key) { return localStorage.getItem(key); }; gmFuncs.GM_deleteValue = function (key) { return localStorage.removeItem(key); }; gmFuncs.GM_addStyle = function (doc, css) { var head, style; head = document.getElementsByTagName("head")[0]; if (!head) { return; } style = document.createElement("style"); style.type = "text/css"; style.innerHTML = css; head.appendChild(style); }; gmFuncs.GM_listValues = function () { var list = []; for(var i=0, len=localStorage.length; i<len; i++) { list.push(localStorage.key(i)); } return list; }; // set ---- if(typeof GM_setValue == 'function') { try { if(GM_setValue.toString().indexOf("not supported") > -1) { GM_setValue = gmFuncs.GM_setValue; } } catch(e) {} } else { GM_setValue = gmFuncs.GM_setValue; } if(typeof GM_getValue == 'function') { try { if(GM_getValue.toString().indexOf("not supported") > -1) { GM_getValue = gmFuncs.GM_getValue; } } catch(e) {} } else { GM_getValue = gmFuncs.GM_getValue; } if(typeof GM_deleteValue == 'undefined') { GM_deleteValue = gmFuncs.GM_deleteValue; } if(typeof GM_listValues == 'undefined') { GM_listValues = gmFuncs.GM_listValues; } if(typeof GM_addStyle == 'undefined') { GM_addStyle = gmFuncs.GM_addStyle; } }
実際に動かしてみる場合はこちら:https://gist.github.com/1027730
※僕が確認した時は、Chromeでも GM_addStyle() サポートされてたんですけど、もしかしてChrome9.0bだからですかね。。一旦ダウングレードしてみます。
Opera11にGM_addStyle()がなかったので追記(記事の主題からははずれますが)。引用元:GM_addStyleの実装と最適化 - 0xFF
注意事項
Web Storage(localStorageオブジェクト)は、GM_*Value(s)関数と似た働きをしてくれるんですが、以下の2つには注意しましょう。。
- 同じorigin上でしかデータが共有できない
- 他のスクリプトから書きかえられる可能性がある
GM_*Value(s)系関数は、複数のドメイン間でも関係なしに値を取得・設定できます。
例えば、GoogleのTOPページでGM_setValue("hoge", "fuga");としたあと、YahooのTOPページでGM_getValue("hoge");とすると、"fuga"が出力されます。
originに関する参考資料:同一生成元ポリシー - MDN
ところで
毎回if文で「GM_hogehoge == 'undefined'」書いてるのうざい
関数にオブジェクト渡して処理、なんてことを真っ先に考えたんですが、
undefinedなオブジェクトは関数に渡す前で例外吐いちゃうんですね。。
var isNotSupported = function(gmObj) { return (typeof gmObj == 'undefined' || gmObj.toString().indexOf("not supported") > -1); }; if(isNotSupported(GM_getValue)) { // 例外発生 GM_getValue = function (key) { return localStorage.getItem(key); }; }
これを避けるために、"GM_getValue"みたいに文字列を関数に渡して処理する方法も考えたんですが、Firefoxでもtypeof Object == 'undefined' の判定をするとtrueになってしまいました。
var isNotSupported = function(gmStr) { return (typeof unsafeWindow[gmStr] == 'undefined' // Firefoxでもtrue || unsafeWindow[gmStr].toString().indexOf("not supported") > -1); }; if(isNotSupported("GM_getValue")) { GM_getValue = function (key) { return localStorage.getItem(key); }; }
どうやら、GM_*の関数はビルドイン関数のような扱いになっていて、windowオブジェクトやunsafeWindowオブジェクトに属していないようです。。
alert(typeof window["GM_getValue"]); // undefined alert(typeof unsafeWindow["GM_getValue"]); // undefined alert(typeof GM_getValue); // function
クロスブラウザ対策を行ったクラスを作った方がスマートかも
すでにスクリプト作っちゃってて対策するのめんどくさいんだけど!っていう人以外は、関数をオーバーライドするのではなく、自分でクラスを作ってそれを使った方が柔軟に対応できそうです。
あとここまで書いておいてなんですけど、FirefoxもWeb Storageサポート済みです。事足りるなら一本化するのもありかも。
追記:Firefox4に対応
Firefox4から、GM_setValue#toString() を行うと例外エラーが発生するようになりました。そのため、try-catchで対処しています。
try-catch嫌いなので他の方法取りたかったんですが、ぱっと思い浮かびませんでした…。
eval使うともう少しすっきりするんですが、キモいので使ってません。
Firefox4RC版で、以下のスクリプトがエラーを吐いてしまうことを確認しました。調査中です。。
Firefox4に対応させました。
- 25 http://pipes.yahoo.com/pipes/pipe.info?_id=0kJqAOKW3RGniq6n1ZzWFw
- 22 http://pipes.yahoo.com/pipes/pipe.info?_id=3572f9da2c8db3951cc02c59f68f43ba
- 4 http://reader.livedoor.com/reader/
- 2 http://longurl.org
- 2 http://pipes.yahoo.com/pipes/pipe.info?_id=a6e4f0188cd15a76dfd4aa8632af4700
- 2 http://www.google.co.jp/search?hl=ja&q=javascript+処理+順番&aq=6&aqi=g10&aql=&oq=javascript+処理&gs_rfai=
- 1 http://b.hatena.ne.jp/entrymobile/27600737
- 1 http://b.hatena.ne.jp/hotentry/it
- 1 http://b.hatena.ne.jp/nanakoso/favorite
- 1 http://b.hatena.ne.jp/t/javascript?sort=hot&threshold=3
