2 # Copyright Simon Lydell 2015, 2016.
4 # This file is part of VimFx.
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.
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.
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/>.
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.
25 namespace = (name) -> "#{ADDON_PATH}/#{name}"
29 FRAME_SCRIPT_ENVIRONMENT
31 Cc['@mozilla.org/globalmessagemanager;1']
32 .getService(Ci.nsIMessageListenerManager)
34 load = (name, messageManager = defaultMM) ->
35 # Randomize URI to work around bug 1051238.
36 uri = "#{ADDON_PATH}/content/#{name}.js?#{Math.random()}"
37 messageManager.loadFrameScript(uri, true)
39 messageManager.removeDelayedFrameScript(uri)
42 listen = (name, listener, messageManager = defaultMM) ->
43 namespacedName = namespace(name)
44 fn = invokeListener.bind(null, listener)
45 messageManager.addMessageListener(namespacedName, fn)
47 messageManager.removeMessageListener(namespacedName, fn)
50 listenOnce = (name, listener, messageManager = defaultMM) ->
51 namespacedName = namespace(name)
53 messageManager.removeMessageListener(namespacedName, fn)
54 return invokeListener(listener, data)
55 messageManager.addMessageListener(namespacedName, fn)
58 send = (name, data = null, messageManager = defaultMM, callback = null) ->
59 if typeof messageManager == 'function'
60 callback = messageManager
61 messageManager = defaultMM
65 callbackName = "#{name}:callback:#{callbackCounter}"
67 listenOnce(callbackName, callback, messageManager)
69 namespacedName = namespace(name)
70 wrappedData = {data, callback: callbackName}
71 if messageManager.broadcastAsyncMessage
72 messageManager.broadcastAsyncMessage(namespacedName, wrappedData)
74 messageManager.sendAsyncMessage(namespacedName, wrappedData)
76 # Unwraps the data from `send` and invokes `listener` with it.
77 invokeListener = (listener, {name, data: {data, callback} = {}, target}) ->
78 return listener(data, {name, target, callback})
80 # Note: This is a synchronous call. It should only be used when absolutely
81 # needed, such as in an event listener which needs to suppress the event based
82 # on the return value.
84 [result] = defaultMM.sendSyncMessage(namespace(name), {data})