]> git.gir.st - VimFx.git/blob - extension/lib/message-manager.coffee
fix hintsmode clicking in ff56, squash some exceptions
[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 try
13 Cc['@mozilla.org/globalmessagemanager;1']
14 .getService(Ci.nsIMessageListenerManager)
15 catch
16 Cc['@mozilla.org/globalmessagemanager;1'].getService()
17
18 defaultOptions = {
19 messageManager: defaultMessageManager
20 onShutdown: module.onShutdown
21 prefix: ''
22 }
23
24 load = (uri, options = {}) ->
25 args = Object.assign({}, defaultOptions, options)
26 # Randomize URI to work around bug 1051238.
27 randomizedUri = "#{uri}?#{Math.random()}"
28 args.messageManager.loadFrameScript(randomizedUri, true)
29 args.onShutdown(->
30 args.messageManager.removeDelayedFrameScript(randomizedUri)
31 )
32
33 listen = (name, listener, options = {}) ->
34 args = Object.assign({}, defaultOptions, options)
35 namespacedName = namespace(name, args.prefix)
36 fn = (data) -> invokeListener?(listener, args, data)
37 args.messageManager.addMessageListener(namespacedName, fn)
38 args.onShutdown(->
39 args.messageManager.removeMessageListener(namespacedName, fn)
40 )
41
42 listenOnce = (name, listener, options = {}) ->
43 args = Object.assign({}, defaultOptions, options)
44 namespacedName = namespace(name, args.prefix)
45 fn = (data) ->
46 args.messageManager.removeMessageListener(namespacedName, fn)
47 return invokeListener?(listener, args, data)
48 args.messageManager.addMessageListener(namespacedName, fn)
49
50 callbackCounter = 0
51 send = (name, data = null, callback = null, options = {}) ->
52 args = Object.assign({}, defaultOptions, options)
53
54 callbackName = null
55 if callback
56 callbackName = "#{name}:callback:#{callbackCounter}"
57 callbackCounter += 1
58 listenOnce(callbackName, callback, args)
59
60 namespacedName = namespace(name, args.prefix)
61 wrappedData = {data, callbackName}
62
63 # Message Manager methods may be missing on shutdown.
64 if args.messageManager.broadcastAsyncMessage
65 args.messageManager.broadcastAsyncMessage?(namespacedName, wrappedData)
66 else
67 try # NOTE: throws NS_ERROR_NOT_INITIALIZED sometimes
68 args.messageManager.sendAsyncMessage?(namespacedName, wrappedData)
69
70 # Unwraps the data from `send` and invokes `listener` with it.
71 invokeListener = (listener, args, {data: {data, callbackName} = {}, target}) ->
72 callback =
73 if callbackName
74 (data = null) ->
75 send(callbackName, data, null, Object.assign({}, args, {
76 messageManager: target.messageManager ? target
77 }))
78 else
79 null
80 return listener(data, callback, target)
81
82 # Note: This is a synchronous call. It should only be used when absolutely
83 # needed, such as in an event listener which needs to suppress the event based
84 # on the return value.
85 get = (name, data) ->
86 namespacedName = namespace(name, defaultOptions.prefix)
87 [result] = defaultMessageManager.sendSyncMessage(namespacedName, {data})
88 return result
89
90 module.exports = {
91 load
92 listen
93 listenOnce
94 send
95 get
96 }
Imprint / Impressum