]> git.gir.st - VimFx.git/blob - extension/lib/message-manager.coffee
Change license to MIT
[VimFx.git] / extension / lib / message-manager.coffee
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.
5
6 namespace = (name, prefix) -> "#{ADDON_PATH}/#{BUILD_TIME}/#{prefix}#{name}"
7
8 defaultMessageManager =
9 if IS_FRAME_SCRIPT
10 FRAME_SCRIPT_ENVIRONMENT
11 else
12 Cc['@mozilla.org/globalmessagemanager;1']
13 .getService(Ci.nsIMessageListenerManager)
14
15 defaultOptions = {
16 messageManager: defaultMessageManager
17 onShutdown: module.onShutdown
18 prefix: ''
19 }
20
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)
26 args.onShutdown(->
27 args.messageManager.removeDelayedFrameScript(randomizedUri)
28 )
29
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)
35 args.onShutdown(->
36 args.messageManager.removeMessageListener(namespacedName, fn)
37 )
38
39 listenOnce = (name, listener, options = {}) ->
40 args = Object.assign({}, defaultOptions, options)
41 namespacedName = namespace(name, args.prefix)
42 fn = (data) ->
43 args.messageManager.removeMessageListener(namespacedName, fn)
44 return invokeListener?(listener, args, data)
45 args.messageManager.addMessageListener(namespacedName, fn)
46
47 callbackCounter = 0
48 send = (name, data = null, callback = null, options = {}) ->
49 args = Object.assign({}, defaultOptions, options)
50
51 callbackName = null
52 if callback
53 callbackName = "#{name}:callback:#{callbackCounter}"
54 callbackCounter += 1
55 listenOnce(callbackName, callback, args)
56
57 namespacedName = namespace(name, args.prefix)
58 wrappedData = {data, callbackName}
59
60 # Message Manager methods may be missing on shutdown.
61 if args.messageManager.broadcastAsyncMessage
62 args.messageManager.broadcastAsyncMessage?(namespacedName, wrappedData)
63 else
64 args.messageManager.sendAsyncMessage?(namespacedName, wrappedData)
65
66 # Unwraps the data from `send` and invokes `listener` with it.
67 invokeListener = (listener, args, {data: {data, callbackName} = {}, target}) ->
68 callback =
69 if callbackName
70 (data = null) ->
71 send(callbackName, data, null, Object.assign({}, args, {
72 messageManager: target.messageManager ? target
73 }))
74 else
75 null
76 return listener(data, callback, target)
77
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.
81 get = (name, data) ->
82 namespacedName = namespace(name, defaultOptions.prefix)
83 [result] = defaultMessageManager.sendSyncMessage(namespacedName, {data})
84 return result
85
86 module.exports = {
87 load
88 listen
89 listenOnce
90 send
91 get
92 }
Imprint / Impressum