forked from dequelabs/axe-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrespondable.js
More file actions
108 lines (93 loc) · 2.67 KB
/
respondable.js
File metadata and controls
108 lines (93 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { v4 as createUuid } from './uuid';
import assert from './assert';
import { setDefaultFrameMessenger } from './frame-messenger';
let closeHandler;
let postMessage;
const topicHandlers = {};
/**
* Post a message to a window who may or may not respond to it.
* @param {Window} win The window to post the message to
* @param {String} topic The topic of the message
* @param {Object} message The message content
* @param {Boolean} keepalive Whether to allow multiple responses - default is false
* @param {Function} replyHandler The function to invoke when/if the message is responded to
*/
export default function respondable(
win,
topic,
message,
keepalive,
replyHandler
) {
const data = {
topic,
message,
channelId: `${createUuid()}:${createUuid()}`,
keepalive
};
return postMessage(win, data, replyHandler);
}
/**
* Handle incoming window messages
* @param {Object} data
* @param {Function} responder
*/
function messageListener(data, responder) {
const { topic, message, keepalive } = data;
const topicHandler = topicHandlers[topic];
if (!topicHandler) {
return;
}
try {
topicHandler(message, keepalive, responder);
} catch (error) {
axe.log(error);
responder(error, keepalive);
}
}
/**
* Update how respondable communicates with iframes.
* @param {Function} frameHandler Object with open, post, and close functions
*/
respondable.updateMessenger = function updateMessenger({ open, post }) {
assert(typeof open === 'function', 'open callback must be a function');
assert(typeof post === 'function', 'post callback must be a function');
if (closeHandler) {
closeHandler();
}
const close = open(messageListener);
if (close) {
assert(
typeof close === 'function',
'open callback must return a cleanup function'
);
closeHandler = close;
} else {
closeHandler = null;
}
postMessage = post;
};
/**
* Subscribe to messages sent via the `respondable` module.
*
* Axe._load uses this to listen for messages from other frames
*
* @param {String} topic The topic to listen to
* @param {Function} topicHandler The function to invoke when a message is received
*/
respondable.subscribe = function subscribe(topic, topicHandler) {
assert(
typeof topicHandler === 'function',
'Subscriber callback must be a function'
);
assert(!topicHandlers[topic], `Topic ${topic} is already registered to.`);
topicHandlers[topic] = topicHandler;
};
/**
* checks if the current context is inside a frame
* @return {Boolean}
*/
respondable.isInFrame = function isInFrame(win = window) {
return !!win.frameElement;
};
setDefaultFrameMessenger(respondable);