]> git.gir.st - VimFx.git/blob - extension/lib/message-manager.coffee
Merge branch 'master' into develop
[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 fn = (data) ->
61 args.messageManager.removeMessageListener(namespacedName, fn)
62 return invokeListener(listener, args, data)
63 args.messageManager.addMessageListener(namespacedName, fn)
64
65 callbackCounter = 0
66 send = (name, data = null, callback = null, options = {}) ->
67 args = Object.assign({}, defaultOptions, options)
68
69 callbackName = null
70 if callback
71 callbackName = "#{name}:callback:#{callbackCounter}"
72 callbackCounter += 1
73 listenOnce(callbackName, callback, args)
74
75 namespacedName = namespace(name, args.prefix)
76 wrappedData = {data, callbackName}
77 if args.messageManager.broadcastAsyncMessage
78 args.messageManager.broadcastAsyncMessage(namespacedName, wrappedData)
79 else
80 args.messageManager.sendAsyncMessage(namespacedName, wrappedData)
81
82 # Unwraps the data from `send` and invokes `listener` with it.
83 invokeListener = (listener, args, {data: {data, callbackName} = {}, target}) ->
84 callback =
85 if callbackName
86 (data = null) ->
87 send(callbackName, data, null, Object.assign({}, args, {
88 messageManager: target.messageManager ? target
89 }))
90 else
91 null
92 return listener(data, callback, target)
93
94 # Note: This is a synchronous call. It should only be used when absolutely
95 # needed, such as in an event listener which needs to suppress the event based
96 # on the return value.
97 get = (name, data) ->
98 namespacedName = namespace(name, defaultOptions.prefix)
99 [result] = defaultMessageManager.sendSyncMessage(namespacedName, {data})
100 return result
101
102 module.exports = {
103 load
104 listen
105 listenOnce
106 send
107 get
108 }
Imprint / Impressum