Este tutorial descreve o uso de APIS de baixo nível. Estas APIs estão ainda em desenvolvimento, e nós esperamos fazer mudanças incompatíveis nela em lançamentos futuros.
O guia de programação de eventos dirigidos com SDK descreve como consumir eventos: isto é, como escutar eventos gerados pelo alvos de evento. Por exemplo, você pode escutar ao evento evento ready
do módulo tab ou o event show do objeto Panel
.
Com o SDK, também é simples implementar seus próprios alvos de eventos. Isto é especialmente útil se você quiser construir seus próprios módulos, ou organizar seu add-on melhor ou permitir a outros desenvolvedores reusar seu código. Se você usa o framework de eventos do SDK para seus alvos de eventos, os usuários de seus módulos podem escutar pelos eventos usando a API de evento padrão do SDK.
Neste tutorial nów criaremos parte de um módulo para acessar a API Local do navegador. Ele emitirá eventos quando o usuário adicionar e visitar um favorito, permitindo aos usuários escutar estes eventos usando a API de evento padrão do SDK.
Usando a API Local
Primeiro, vamos escrever algun código usando a API Local que registra as URIs do favorito que o usuário adicinou.
Crie uma novo diretório chamado "bookmarks", navegue até ele, e execute jpm init
, aceitando todos os padrões. Então abra o "index.js" e adicione o seguinte código:
var {Cc, Ci, Cu} = require("chrome"); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); var bookmarkService = Cc["@mozilla.org/browser/nav-bookmarks-service;1"] .getService(Ci.nsINavBookmarksService); var bookmarkObserver = { onItemAdded: function(aItemId, aFolder, aIndex) { console.log("added ", bookmarkService.getBookmarkURI(aItemId).spec); }, onItemVisited: function(aItemId, aVisitID, time) { console.log("visited ", bookmarkService.getBookmarkURI(aItemId).spec); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]) }; exports.main = function() { bookmarkService.addObserver(bookmarkObserver, false); }; exports.onUnload = function() { bookmarkService.removeObserver(bookmarkObserver); }
Tente executar este add-on, adicionando e visitando favoritos, e observando a saída no console.
Módulos como Alvos de Evento
Nós podemos adaptar esse código em módulos separados que expõe a interface de evento padrão do SDK.
Para fazer isso nós usaremos o módulo event/core
.
Crie um novo arquivo no "lib" chamado "bookmarks.js", e adicione o seguinte código:
var { emit, on, once, off } = require("sdk/event/core"); var {Cc, Ci, Cu} = require("chrome"); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); var bookmarkService = Cc["@mozilla.org/browser/nav-bookmarks-service;1"] .getService(Ci.nsINavBookmarksService); var bookmarkObserver = { onItemAdded: function(aItemId, aFolder, aIndex) { emit(exports, "added", bookmarkService.getBookmarkURI(aItemId).spec); }, onItemVisited: function(aItemId, aVisitID, time) { emit(exports, "visited", bookmarkService.getBookmarkURI(aItemId).spec); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]) }; bookmarkService.addObserver(bookmarkObserver, false); exports.on = on.bind(null, exports); exports.once = once.bind(null, exports); exports.removeListener = function removeListener(type, listener) { off(exports, type, listener); };
Este código implementa um módulo que pode emitir eventos added
e visited
. Ele duplica o código anterior, mas com um pouco de mudanças:
- importe
emit()
,on()
,once()
, eoff()
doevent/core
- substitua as funções de escuta com chamadas para
emit()
, passando o tipo de evento apropriado - exporte sua própria API de evento. Este consiste de três funções:
on()
: inicia a escuta pelo evento ou um dado tipoonce()
: escuta pela ocorrência de um dado evento, e então pararemoveListener()
: para a escuta por eventos de um dado tipo
O on()
e once()
exporta delegação a uma função correspondente do event/core
, e usa bind()
para passar o objeto exports
por si só como o argumento target(alvo)
à função subjacente. A função removeListener()
é implementada pela chamada da função subjacente off()
.
Nós podemos usar este módulo do mesmo modo que nós usamos qualquer outro módulo que emite eventos a nível de módulo, tais como tabs
. Por exemplo, nós podemos adaptar o "index.js" como segue:
var bookmarks = require("./bookmarks"); function logAdded(uri) { console.log("added: " + uri); } function logVisited(uri) { console.log("visited: " + uri); } exports.main = function() { bookmarks.on("added", logAdded); bookmarks.on("visited", logVisited); }; exports.onUnload = function() { bookmarks.removeListener("added", logAdded); bookmarks.removeListener("visited", logVisited); }
Classes como Alvos de Eventos
Às vezes nós queremos emitir eventos à nível de objetos individuais, em vez de à nível de módulo.
Para fazer isto, nós podemos herdar da classe EventTarget
do SDK. EventTarget
fornece uma implementação das funções necessárias a adicionar e remover escutas: on()
, once()
, e removeListener()
.
Neste exemplo, nós poderíamos definir uma classe BookmarkManager
que herda do EventTarget
e emite eventos added
e visited
.
Abra o "bookmarks.js" e substitua seu conteúdo com este código:
var { emit } = require("sdk/event/core"); var { EventTarget } = require("sdk/event/target"); var { Class } = require("sdk/core/heritage"); var { merge } = require("sdk/util/object"); var {Cc, Ci, Cu} = require("chrome"); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); var bookmarkService = Cc["@mozilla.org/browser/nav-bookmarks-service;1"] .getService(Ci.nsINavBookmarksService); function createObserver(target) { var bookmarkObserver = { onItemAdded: function(aItemId, aFolder, aIndex) { emit(target, "added", bookmarkService.getBookmarkURI(aItemId).spec); }, onItemVisited: function(aItemId, aVisitID, time) { emit(target, "visited", bookmarkService.getBookmarkURI(aItemId).spec); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]) }; bookmarkService.addObserver(bookmarkObserver, false); } var BookmarkManager = Class({ extends: EventTarget, initialize: function initialize(options) { EventTarget.prototype.initialize.call(this, options); merge(this, options); createObserver(this); } }); exports.BookmarkManager = BookmarkManager;
O código para interagir com a API Local é o mesmo que aqui. Porém:
- nós estamos agora importando de quatro módulos:
event/core
nos dáemit()
: note que nós não precisamoson
,once
, ouoff
, desde que nós usaremosEventTarget
para adicionar e remover escutasevent/target
nos dáEventTarget
, que implementa a interface para adicionar e remover escutascore/heritage
nos dáClass()
, que nós podemos usar para herdar doEventTarget
util/object
nos dámerge()
, que apenas simplifica a configuração das propriedades doBookmarkManager
- nós usamos classe para herdar do
EventTarget
. Em sua funçãoinitialize()
, nós:- chamar o inicializador de classe base
- use
merge()
para copiar qualquer opção fornecida dentro do novíssimo objeto criado - chama
createObserver()
, passando o novíssimo objeto criado como o alvo do evento
createObserver()
é o mesmo do exemplo anterior, exceto que noemit()
nós passamos oBookmarkManager
criado como o alvo do evento
Para usar este alvo de evento nós podemos criar ele e chamar a funções on()
, once()
, e removeListener()
que ele herdou:
var bookmarks = require("./bookmarks"); var bookmarkManager = bookmarks.BookmarkManager({}); function logAdded(uri) { console.log("added: " + uri); } function logVisited(uri) { console.log("visited: " + uri); } exports.main = function() { bookmarkManager.on("added", logAdded); bookmarkManager.on("visited", logVisited); }; exports.onUnload = function() { bookmarkManager.removeListener("added", logAdded); bookmarkManager.removeListener("visited", logVisited); }
Implementando uma opção "onEvent"
Finalmente, a maioria dos alvos de eventos aceitam opções na forma "onEvent", onde "Event" é o nome do evento com a primeira letra em maiúsculo. Por exemplo, você pode escutar o evento show do objeto Panel
ou chamando:
myPanel.on("show", listenerFunction);
ou passando a opção onShow
para o construtor do Painel:
var myPanel = require("sdk/panel").Panel({ onShow: listenerFunction, contentURL: "https://en.wikipedia.org/w/index.php" });
Se sua classe herda do EventTarget
, opções como this
são automaticamente manipuladas para você. Por exemplo, dada a implementação do BookmarkManager
acima, seu "index.js" seria reescrito como isto:
var bookmarks = require("./bookmarks"); function logAdded(uri) { console.log("added: " + uri); } function logVisited(uri) { console.log("visited: " + uri); } var bookmarkManager = bookmarks.BookmarkManager({ onAdded: logAdded, onVisited: logVisited }); exports.onUnload = function() { bookmarkManager.removeListener("added", logAdded); bookmarkManager.removeListener("visited", logVisited); }