1 # This file provides an API a bit more easy to use than the very low-level
2 # Firefox message manager APIs. “Message Management” is all about sending
3 # messages between the main process and frame scripts. There is one frame script
4 # per tab, and only them can access web page content.
6 namespace = (name, prefix) -> "#{ADDON_PATH}/#{BUILD_TIME}/#{prefix}#{name}"
8 defaultMessageManager =
10 FRAME_SCRIPT_ENVIRONMENT
12 Cc['@mozilla.org/globalmessagemanager;1']
13 .getService(Ci.nsIMessageListenerManager)
16 messageManager: defaultMessageManager
17 onShutdown: module.onShutdown
21 load = (uri, options = {}) ->
22 args = Object.assign({}, defaultOptions, options)
23 # Randomize URI to work around bug 1051238.
24 randomizedUri = "#{uri}?#{Math.random()}"
25 args.messageManager.loadFrameScript(randomizedUri, true)
27 args.messageManager.removeDelayedFrameScript(randomizedUri)
30 listen = (name, listener, options = {}) ->
31 args = Object.assign({}, defaultOptions, options)
32 namespacedName = namespace(name, args.prefix)
33 fn = (data) -> invokeListener?(listener, args, data)
34 args.messageManager.addMessageListener(namespacedName, fn)
36 args.messageManager.removeMessageListener(namespacedName, fn)
39 listenOnce = (name, listener, options = {}) ->
40 args = Object.assign({}, defaultOptions, options)
41 namespacedName = namespace(name, args.prefix)
43 args.messageManager.removeMessageListener(namespacedName, fn)
44 return invokeListener?(listener, args, data)
45 args.messageManager.addMessageListener(namespacedName, fn)
48 send = (name, data = null, callback = null, options = {}) ->
49 args = Object.assign({}, defaultOptions, options)
53 callbackName = "#{name}:callback:#{callbackCounter}"
55 listenOnce(callbackName, callback, args)
57 namespacedName = namespace(name, args.prefix)
58 wrappedData = {data, callbackName}
60 # Message Manager methods may be missing on shutdown.
61 if args.messageManager.broadcastAsyncMessage
62 args.messageManager.broadcastAsyncMessage?(namespacedName, wrappedData)
64 args.messageManager.sendAsyncMessage?(namespacedName, wrappedData)
66 # Unwraps the data from `send` and invokes `listener` with it.
67 invokeListener = (listener, args, {data: {data, callbackName} = {}, target}) ->
71 send(callbackName, data, null, Object.assign({}, args, {
72 messageManager: target.messageManager ? target
76 return listener(data, callback, target)
78 # Note: This is a synchronous call. It should only be used when absolutely
79 # needed, such as in an event listener which needs to suppress the event based
80 # on the return value.
82 namespacedName = namespace(name, defaultOptions.prefix)
83 [result] = defaultMessageManager.sendSyncMessage(namespacedName, {data})