]> git.gir.st - VimFx.git/blob - extension/lib/message-manager.coffee
Fix "invokeListener is not a function" uncaught errors
[VimFx.git] / extension / lib / message-manager.coffee
1 ###
2 # Copyright Simon Lydell 2015, 2016.
3 #
4 # This file is part of VimFx.
5 #
6 # VimFx is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # VimFx is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
18 ###
19
20 # This file provides an API a bit more easy to use than the very low-level
21 # Firefox message manager APIs. “Message Management” is all about sending
22 # messages between the main process and frame scripts. There is one frame script
23 # per tab, and only them can access web page content.
24
25 namespace = (name, prefix) -> "#{ADDON_PATH}/#{prefix}#{name}"
26
27 defaultMessageManager =
28 if IS_FRAME_SCRIPT
29 FRAME_SCRIPT_ENVIRONMENT
30 else
31 Cc['@mozilla.org/globalmessagemanager;1']
32 .getService(Ci.nsIMessageListenerManager)
33
34 defaultOptions = {
35 messageManager: defaultMessageManager
36 onShutdown: module.onShutdown
37 prefix: ''
38 }
39
40 load = (uri, options = {}) ->
41 args = Object.assign({}, defaultOptions, options)
42 # Randomize URI to work around bug 1051238.
43 args.messageManager.loadFrameScript("#{uri}?#{Math.random()}", true)
44 args.onShutdown(->
45 args.messageManager.removeDelayedFrameScript(uri)
46 )
47
48 listen = (name, listener, options = {}) ->
49 args = Object.assign({}, defaultOptions, options)
50 namespacedName = namespace(name, args.prefix)
51 fn = invokeListener.bind(null, listener, args)
52 args.messageManager.addMessageListener(namespacedName, fn)
53 args.onShutdown(->
54 args.messageManager.removeMessageListener(namespacedName, fn)
55 )
56
57 listenOnce = (name, listener, options = {}) ->
58 args = Object.assign({}, defaultOptions, options)
59 namespacedName = namespace(name, args.prefix)
60 # Make a copy of `invokeListener` in case it has been `null`ed out at the time
61 # this runs.
62 _invokeListener = invokeListener.bind(null, listener, args)
63 fn = (data) ->
64 args.messageManager.removeMessageListener(namespacedName, fn)
65 return _invokeListener(data)
66 args.messageManager.addMessageListener(namespacedName, fn)
67
68 callbackCounter = 0
69 send = (name, data = null, callback = null, options = {}) ->
70 args = Object.assign({}, defaultOptions, options)
71
72 callbackName = null
73 if callback
74 callbackName = "#{name}:callback:#{callbackCounter}"
75 callbackCounter += 1
76 listenOnce(callbackName, callback, args)
77
78 namespacedName = namespace(name, args.prefix)
79 wrappedData = {data, callbackName}
80 if args.messageManager.broadcastAsyncMessage
81 args.messageManager.broadcastAsyncMessage(namespacedName, wrappedData)
82 else
83 args.messageManager.sendAsyncMessage(namespacedName, wrappedData)
84
85 # Unwraps the data from `send` and invokes `listener` with it.
86 invokeListener = (listener, args, {data: {data, callbackName} = {}, target}) ->
87 callback =
88 if callbackName
89 (data = null) ->
90 send(callbackName, data, null, Object.assign({}, args, {
91 messageManager: target.messageManager ? target
92 }))
93 else
94 null
95 return listener(data, callback, target)
96
97 # Note: This is a synchronous call. It should only be used when absolutely
98 # needed, such as in an event listener which needs to suppress the event based
99 # on the return value.
100 get = (name, data) ->
101 namespacedName = namespace(name, defaultOptions.prefix)
102 [result] = defaultMessageManager.sendSyncMessage(namespacedName, {data})
103 return result
104
105 module.exports = {
106 load
107 listen
108 listenOnce
109 send
110 get
111 }
Imprint / Impressum