Skip to content
This repository was archived by the owner on Jan 31, 2025. It is now read-only.

Commit 8157803

Browse files
author
Daniel Brain
committed
Updates, features, docs
1 parent c202261 commit 8157803

File tree

2 files changed

+163
-27
lines changed

2 files changed

+163
-27
lines changed

README.md

+30-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ With this, you can set up a listener in one window, have it wait for a post mess
99
and gracefully handle any errors that crop up. You can also set a timeout, to be sure that the other window is responding to you,
1010
and fail gracefully if it does not.
1111

12+
## Features
13+
14+
- Request/response pattern (avoids sending fire-and-forget messages back and forth)
15+
- Don't worry about serialization, just send javascript objects
16+
- Handle error cases gracefully
17+
- The user closed the window you're trying to message
18+
- You sent a message the other window wasn't expecting
19+
- The other window doesn't have any listener set up for your message
20+
- The other window didn't acknowledge your message
21+
- You didn't get a response from the other window in enough time
22+
- Somebody sent you a message you weren't listening for
23+
1224
## Example
1325

1426
```javascript
@@ -17,15 +29,15 @@ and fail gracefully if it does not.
1729

1830
postRobot.listen({
1931

20-
name: 'get_cart',
32+
name: 'getCart',
2133

2234
handler: function(data, callback) {
2335
setTimeout(function() {
2436
return callback(null, {
2537
amount: 1,
2638
shipping: 2
2739
});
28-
}, 3000)
40+
}, 500)
2941
}
3042
});
3143

@@ -34,7 +46,8 @@ postRobot.listen({
3446
postRobot.request({
3547

3648
window: window,
37-
name: 'get_cart',
49+
name: 'getCart',
50+
bridge: window.opener.frames.PayPalBridge.returnToParent,
3851

3952
response: function(err, data) {
4053
if (err) {
@@ -46,4 +59,18 @@ postRobot.request({
4659
timeout: 1000
4760
});
4861

62+
```
63+
64+
## Shortcuts
65+
66+
```
67+
postRobot.on('getCart', function(err, data, callback) {
68+
return callback({
69+
amount: 1
70+
});
71+
});
72+
73+
postRobot.send(window, 'getCart', function(err, data) {
74+
console.log(data);
75+
});
4976
```

index.js

+133-24
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
11

22
window.postRobot = (function() {
33

4+
function noop() {}
5+
6+
if (!window.addEventListener || !window.postMessage) {
7+
8+
if (window.console && window.console.warn) {
9+
console.warn('Browser does not support window.postMessage');
10+
}
11+
12+
return {
13+
message: noop,
14+
listen: noop,
15+
16+
req: noop,
17+
res: noop,
18+
19+
destroy: noop
20+
};
21+
}
22+
423
var POST_MESSAGE_REQUEST = 'post_message_request';
524
var POST_MESSAGE_RESPONSE = 'post_message_response';
25+
var POST_MESSAGE_ACK = 'post_message_ack';
626

727
var POST_MESSAGE_RESPONSE_ACK_SUCCESS = 'success';
828
var POST_MESSAGE_RESPONSE_ACK_ERROR = 'error';
@@ -43,21 +63,54 @@ window.postRobot = (function() {
4363
var hash = Math.random().toString();
4464
responseHandlers[hash] = options;
4565

66+
options.respond = once(function(err, response) {
67+
delete responseHandlers[hash];
68+
return options.response(err, response);
69+
});
70+
71+
if (!options.window.postMessage) {
72+
return options.respond(new Error('Target window does not have postMessage handler'));
73+
}
74+
75+
if (options.window.closed) {
76+
return options.respond(new Error('Target window is closed'));
77+
}
78+
4679
if (options.timeout) {
4780
setTimeout(function() {
48-
if (responseHandlers[hash]) {
49-
var handler = responseHandlers[hash];
50-
delete responseHandlers[hash];
51-
return handler.response(new Error('Post message response timed out after ' + options.timeout + ' ms'));
52-
}
81+
options.respond(new Error('Post message response timed out after ' + options.timeout + ' ms'));
5382
}, options.timeout);
5483
}
5584

56-
return sendMessage(options.window, {
57-
type: POST_MESSAGE_REQUEST,
58-
hash: hash,
59-
name: options.name,
60-
data: options.data || {}
85+
try {
86+
sendMessage(options.window, {
87+
type: POST_MESSAGE_REQUEST,
88+
hash: hash,
89+
name: options.name,
90+
data: options.data || {}
91+
});
92+
} catch (err) {
93+
options.respond(err);
94+
}
95+
96+
setTimeout(function() {
97+
if (!options.ack) {
98+
return options.respond(new Error('No ack for postMessage'));
99+
}
100+
});
101+
}
102+
103+
function quickPostMessageRequest(window, name, data, callback) {
104+
105+
if (!callback) {
106+
callback = data;
107+
data = {};
108+
}
109+
110+
return postMessageRequest({
111+
window: window,
112+
name: name,
113+
response: callback
61114
});
62115
}
63116

@@ -76,6 +129,40 @@ window.postRobot = (function() {
76129
}
77130

78131
requestListeners[options.name] = options;
132+
133+
if (options.window) {
134+
var interval = setInterval(function() {
135+
if (options.window.closed) {
136+
clearInterval(interval);
137+
delete requestListeners[options.name];
138+
139+
if (options.successOnClose) {
140+
options.handler(null, null, noop);
141+
} else {
142+
options.handler(new Error('Post message target window is closed'), null, noop);
143+
}
144+
}
145+
}, 50);
146+
}
147+
}
148+
149+
function postMessageListenOnce(options) {
150+
return postMessageListen(options);
151+
}
152+
153+
function quickPostMessageListen(name, callback) {
154+
return postMessageListen({
155+
name: name,
156+
handler: callback
157+
});
158+
}
159+
160+
function quickPostMessageListenOnce(name, callback) {
161+
return postMessageListen({
162+
name: name,
163+
handler: callback,
164+
once: true
165+
});
79166
}
80167

81168
function postMessageListener(event) {
@@ -92,7 +179,17 @@ window.postRobot = (function() {
92179
return;
93180
}
94181

95-
if (message.type === POST_MESSAGE_REQUEST) {
182+
if (message.type === POST_MESSAGE_ACK) {
183+
184+
var options = responseHandlers[message.hash];
185+
186+
if (!options) {
187+
throw new Error('No handler found for post message ack');
188+
}
189+
190+
options.ack = true;
191+
192+
} else if (message.type === POST_MESSAGE_REQUEST) {
96193

97194
var successResponse = once(function successResponse(response) {
98195
return sendMessage(event.source, {
@@ -114,15 +211,26 @@ window.postRobot = (function() {
114211
});
115212
});
116213

117-
if (!requestListeners[message.name]) {
214+
var listener = requestListeners[message.name];
215+
216+
if (!listener) {
118217
return errorResponse(new Error('No postmessage request handler for ' + message.name));
119218
}
120219

220+
if (listener.window && listener.window !== window) {
221+
return;
222+
}
223+
224+
sendMessage(event.source, {
225+
type: POST_MESSAGE_ACK,
226+
hash: message.hash
227+
});
228+
121229
var result;
122230

123231
try {
124232

125-
result = requestListeners[message.name].handler(message.data, function(err, response) {
233+
result = requestListeners[message.name].handler(null, message.data, function(err, response) {
126234
return err ? errorResponse(err) : successResponse(response);
127235
});
128236

@@ -136,17 +244,16 @@ window.postRobot = (function() {
136244

137245
} else if (message.type === POST_MESSAGE_RESPONSE) {
138246

139-
if (!responseHandlers[message.hash]) {
140-
return;
141-
}
142-
143247
var handler = responseHandlers[message.hash];
144-
delete responseHandlers[message.hash];
248+
249+
if (!handler) {
250+
throw new Error('No handler found for post message response');
251+
}
145252

146253
if (message.ack === POST_MESSAGE_RESPONSE_ACK_ERROR) {
147-
return handler.response(message.error);
254+
return handler.respond(message.error);
148255
} else if (message.ack === POST_MESSAGE_RESPONSE_ACK_SUCCESS) {
149-
return handler.response(null, message.response);
256+
return handler.respond(null, message.response);
150257
}
151258
}
152259
};
@@ -160,9 +267,11 @@ window.postRobot = (function() {
160267
return {
161268
request: postMessageRequest,
162269
listen: postMessageListen,
163-
destroy: postMessageDestroy
164-
};
165-
})();
166-
167270

271+
send: quickPostMessageRequest,
272+
on: quickPostMessageListen,
273+
once: quickPostMessageListenOnce,
168274

275+
destroy: postMessageDestroy
276+
};
277+
})();

0 commit comments

Comments
 (0)