More Related Content Similar to Jetpack Library 事始め (20) Jetpack Library 事始め3. Add-on SDK (Jetpack SDK) とは? 現在開発中の、新しい拡張開発キット。 XULなどの知識を必要とせず、HTML, JavaScript, CSSの知識だけで拡張が開発できるかも。 API は Firefox のバージョンに非依存。拡張を再パッケージングするだけで Firefox の新しいバージョンに対応できるはず。 開発した拡張は再起動不要でインストール/アンインストール可能。 サードパーティが自由に API を追加できる。 5. PrototypeとSDK Jetpack Jetpack Jetpack Jetpack Jetpack Jetpack API (Jetpack Prototype 拡張) Core Core Core Firefox Firefox Jetpack Prototype Add-on SDK 6. Add-on SDK 1.0b1 の API(addon-kit) ページコンテンツの変更 ウィンドウ操作・タブ操作 ウィジェット表示・パネル表示 コンテキストメニュー表示 選択範囲の取得 HTTP リクエスト送信・DOM 操作 クリップボードの取得・更新 アラートメッセージ表示 プライベートブラウジングの開始・終了 ストレージへの情報保存 以上! 7. Add-on SDK 1.0b1 の API(addon-kit) 標準 API でGreaseMonkey+α のことはできる。 が、XUL ベースの拡張に比べると、できることは限られている。 ブラウザ自体のUIを拡張できるのはウィジェットとコンテキストメニューのみ 低レベル API を使って自作ライブラリを作れば、なんでもできる! 8. Add-on SDK の低レベル API(api-utils) Components オブジェクトへのアクセス {Cc, Ci, Cu, Cr, Cm, components} = require(“chrome”); tabbrowser要素やwindow要素へのアクセス require(“tab-browser”) require(“window-utils”) API 提供用のヘルパ関数 require(“unload”).ensure() require(“api-utils”).publicConstructor() require(“errors”). catchAndLog() 12. unload モジュール function Foo() { // 変更処理 require("unload").ensure(this); } Foo.prototype = { unload: function(reason) { // 復帰処理 } }; function bar() { // 変更処理 require("unload").when( function(reason){ // 復帰処理 }); } ensure 関数にオブジェクトを登録する。 終了時には、オブジェクトごとに 1 回ずつ unload 関数が実行される。 when関数にコールバック関数を登録する。 複数回 when を呼び出すと、その回数分 処理が実行される。 13. MyExtension 2.0 MyExtension 1.0 変えちゃダメ MyLibrary 2.0 2) バージョン非依存 MyLibrary 1.0 変わらないはず addon-kit 2.x addon-kit 1.0b1 変わるかも api-utils 2.x api-utils 1.0b1 変わるかも Firefox 5.x Firefox 4.0 15. E10S (Electrolysis) とは? firefox.exe 「プロセス分離」のコードネーム。 今後、ブラウザ本体と Web ページのコンテンツと Jetpack 拡張は、それぞれ別プロセスで動作するようになる。 content process ←メッセージ通信-> jetpack process × 直接アクセスはできない 16. コンテンツプロセスの分離を考慮した API varpageSourceItem = contextMenu.Item({ label: "Edit Page Source", contentScript: 'on("click", function (node, data) {' + ' postMessage(document.URL);' + '});', onMessage: function (pageURL){ editSource(pageURL); } }); 別プロセスで動作するスクリプト メッセージ通信 プロセス間で関数オブジェクトは受け渡しできないので、 コンテンツプロセスで動作する部分はスクリプトを文字列もしくは URLで受け渡す。 JSON 形式に変換可能なオブジェクトはメッセージ通信で受け渡し可能。 17. content モジュール for (window in require("window-utils").windowIterator()) { require("content").Worker({ window: window, contentScript: 'postMessage("message!");', onMessage: function(data) { console.log(data); } }); } Worker として登録したスクリプトは対象の window 上で動作する。 オプションは page-mod や context-menu と同様。 18. Jetpack プロセスの分離を考慮した API cfx run に 「--e10s」オプションを付加することで試行できる。 SDK 本体の対応もこれから。今後の動向に注目。 self-e10s-adapter などは参考になる > cfx run --e10s -b "C:rogram Filesinefieldirefox.exe" … Error: Module 'widget' requires chrome privileges and has no e10s adapter. OK … 20. 3-1) construct/destroy モデル widgets.add(widgets.Widget({ label: …, image: …, onClick: … })); widgets.remove(w); widgets.Widget({ label: …, image: …, onClick: … }); w.destroy(); 時代は construct/destroy モデル! add/ removeモデルはもう古い! コンストラクタの中で初期化処理まで実行する。 明示的に変更を元に戻す時は destroy メソッドを使う。 21. コンストラクタ作成時に便利な関数 new ClassName({…}) でも ClassName({…}) だけでもオブジェクトを作れるようにする。 require(“api-utils”).publicConstructor() オプションの内容をチェックする。 require(“api-utils”).validateOptions() Array もしくは スカラ値を受け取るプロパティを作る。 require(“collection”).addCollectionProperty() 22. 3-2) EventEmitterモデル tabs.onOpen =function(){…}; tabs.onReady = function(){…}; tabs.onActivate =function(){ …}; tabs.onDeactivate = function(){ …}; tabs.on(‘Open’,function(){…}); tabs.on(‘Ready’, function(){…}); tabs.on(‘Activate’, function(){ …}); tabs.on(‘Deactivate’, function(){ …}); 時代は EventEmitterモデル! onXXXプロパティはもう古い! EventEmitterを使うことで、全てのイベントについて _emit() でのイベント送信、on() でのイベント受信に統一できる。 23. events モジュール const { EventEmitter } = require("events"); var object = EventEmitter.compose({ constructor: function() {…}, fire: function() { this._emit('event1'); } })(); object.on('event1', function(){ console.log("Event Fired!"); }); object.fire(); EventEmitter.compose()() は Trait という形のオブジェクトを返す。 _emit() など 「_」から始まるメソッドは、this からしか呼び出せない。 31. 使い方 const locationBar = require("location-bar"); const tabs = require("tabs"); locationBar.Icon({ label: "Mozilla website", contentURL: "http://www.mozilla.org/favicon.ico", onClick: function() { tabs.open("http://www.mozilla.org/"); } }); locationBar.Icon({ label: "Google website", contentURL: "http://www.google.com/favicon.ico", onClick: function() { tabs.open("http://www.google.com/"); } }); 33. コンストラクタ:オプションチェック const apiUtils = require("api-utils"); const { EventEmitter } = require("events"); const windowUtils = require("window-utils"); var icons = []; exports.Icon = EventEmitter.compose({ constructor: function Icon(options) { options = apiUtils.validateOptions(options, { label: { is: ["string"] }, tooltip: { is: ["null", "undefined", "string"] }, contentURL: { is: ["string"] }, onClick: { is: ["null", "undefined", "function"] } }); 34. コンストラクタ:初期化 this.id = "locationbaricon:" + require("xpcom").makeUuid().toString(); this._label = options.label; this.tooltip = ("tooltip" in options) ? options.tooltip : this._label this.contentURL = options.contentURL; if ("onClick" in options) { this.on("click", options.onClick); } icons.push(this); for (window in windowUtils.windowIterator()) { addItem(window, this); } }, 35. destroy destroy : function(){ varidx = icons.indexOf(this); if (idx > -1) { icons.splice(idx, 1); } for (window in windowUtils.windowIterator()) { removeItem(window, this); } } }); 36. アイコンの追加 function addItem(window, icon) { var doc = window.document; varurlbar = doc.getElementById('urlbar'); if(urlbar) { var button = doc.createElement('toolbarbutton'); button.setAttribute("id", icon.id); button.setAttribute("tooltiptext", icon.tooltip); button.style.listStyleImage = 'url(' + icon.contentURL + ')'; button.addEventListener('click', function() icon._emit('click'), false); vargoButton = doc.getElementById('urlbar-go-button'); urlbar.insertBefore(button, goButton); } } 37. アイコンの削除 function removeItem(window, icon) { var doc = window.document; varurlbar = doc.getElementById('urlbar'); if(urlbar) { var button = doc.getElementById(icon.id); urlbar.removeChild(button); } } 38. ウィンドウの監視 varwindowManager = { init: function () { varwindowTracker = new (windowUtils.WindowTracker)(this); require("unload").ensure(windowTracker); }, onTrack: function (window) { for(vari=0; i<icons.length; i++){ addItem(window, icons[i]); } }, onUntrack: function (window) { for(vari=0; i<icons.length; i++){ removeItem(window, icons[i]); } } } windowManager.init();