|
1 | 1 | /**@license
|
2 |
| - * sysend.js - send messages between browser windows/tabs version 1.14.3 |
| 2 | + * sysend.js - send messages between browser windows/tabs version 1.15.0 |
3 | 3 | *
|
4 |
| - * Copyright (C) 2014-2022 Jakub T. Jankiewicz <https://jcubic.pl/me> |
| 4 | + * Copyright (C) 2014-2023 Jakub T. Jankiewicz <https://jcubic.pl/me> |
5 | 5 | * Released under the MIT license
|
6 | 6 | *
|
7 | 7 | * The idea for localStorage implementation came from this StackOverflow question:
|
|
88 | 88 | serializer.from = from;
|
89 | 89 | return sysend;
|
90 | 90 | },
|
91 |
| - proxy: function() { |
92 |
| - [].slice.call(arguments).forEach(function(url) { |
| 91 | + proxy: function(...args) { |
| 92 | + args.forEach(function(url) { |
93 | 93 | if (typeof url === 'string' && host(url) !== window.location.host) {
|
94 | 94 | domains = domains || [];
|
95 | 95 | domains.push(origin(url));
|
96 |
| - var iframe = document.createElement('iframe'); |
| 96 | + const iframe = document.createElement('iframe'); |
97 | 97 | iframe.style.width = iframe.style.height = 0;
|
98 | 98 | iframe.style.position = 'absolute';
|
99 | 99 | iframe.style.top = iframe.style.left = '-9999px';
|
100 | 100 | iframe.style.border = 'none';
|
101 |
| - var proxy_url = url; |
| 101 | + let proxy_url = url; |
102 | 102 | if (!url.match(/\.html$/)) {
|
103 | 103 | proxy_url = url.replace(/\/$/, '') + '/proxy.html';
|
104 | 104 | }
|
|
110 | 110 | iframe.removeEventListener('error', handler);
|
111 | 111 | });
|
112 | 112 | iframe.addEventListener('load', function handler() {
|
113 |
| - var win; |
| 113 | + let win; |
114 | 114 | // fix for Safari
|
115 | 115 | // https://stackoverflow.com/q/42632188/387194
|
116 | 116 | try {
|
|
177 | 177 | });
|
178 | 178 | },
|
179 | 179 | list: function() {
|
180 |
| - var id = list_id++; |
181 |
| - var marker = { target: target_id, id: id }; |
182 |
| - var timer = delay(sysend.timeout); |
| 180 | + const id = list_id++; |
| 181 | + const marker = { target: target_id, id: id }; |
| 182 | + const timer = delay(sysend.timeout); |
183 | 183 | return new Promise(function(resolve) {
|
184 |
| - var ids = []; |
| 184 | + const ids = []; |
185 | 185 | sysend.on('__window_ack__', function(data) {
|
186 | 186 | if (data.origin.target === target_id && data.origin.id === id) {
|
187 | 187 | ids.push({
|
|
196 | 196 | });
|
197 | 197 | });
|
198 | 198 | },
|
199 |
| - channel: function() { |
200 |
| - domains = [].slice.apply(arguments).map(origin); |
| 199 | + channel: function(...args) { |
| 200 | + domains = args.map(origin); |
201 | 201 | return sysend;
|
202 | 202 | },
|
203 | 203 | isPrimary: function() {
|
|
210 | 210 | force_ls = true;
|
211 | 211 | }
|
212 | 212 | },
|
| 213 | + rpc: function(object) { |
| 214 | + const prefix = ++rpc_prefix; |
| 215 | + const req = `__${prefix}_rpc_request__`; |
| 216 | + const res = `__${prefix}_rpc_response__`; |
| 217 | + let request_index = 0; |
| 218 | + const timeout = 1000; |
| 219 | + function request(id, method, args = []) { |
| 220 | + const req_id = ++request_index; |
| 221 | + return new Promise((resolve, reject) => { |
| 222 | + sysend.track('message', function handler({data, origin}) { |
| 223 | + if (data.type === res) { |
| 224 | + const { result, error, id: res_id } = data; |
| 225 | + if (origin === id && req_id === res_id) { |
| 226 | + if (error) { |
| 227 | + reject(error); |
| 228 | + } else { |
| 229 | + resolve(result); |
| 230 | + } |
| 231 | + clearTimeout(timer); |
| 232 | + sysend.untrack('message', handler); |
| 233 | + } |
| 234 | + } |
| 235 | + }); |
| 236 | + sysend.post(id, { method, id: req_id, type: req, args }); |
| 237 | + const timer = setTimeout(() => { |
| 238 | + reject(new Error('Timeout error')); |
| 239 | + }, timeout); |
| 240 | + }); |
| 241 | + } |
| 242 | + |
| 243 | + sysend.track('message', async function handler({ data, origin }) { |
| 244 | + if (data.type == req) { |
| 245 | + const { method, args, id } = data; |
| 246 | + const type = res; |
| 247 | + if (Object.hasOwn(object, method)) { |
| 248 | + try { |
| 249 | + unpromise(object[method](...args), function(result) { |
| 250 | + sysend.post(origin, { result, id, type }); |
| 251 | + }, function(error) { |
| 252 | + sysend.post(origin, { error: error.message, id, type }); |
| 253 | + }); |
| 254 | + } catch(e) { |
| 255 | + sysend.post(origin, { error: e.message, id, type }); |
| 256 | + } |
| 257 | + } else { |
| 258 | + sysend.post(origin, { error: 'Method not found', id, type }); |
| 259 | + |
| 260 | + } |
| 261 | + } |
| 262 | + }); |
| 263 | + return Object.fromEntries(Object.keys(object).map(name => { |
| 264 | + return [name, (id, ...args) => { |
| 265 | + if (!id) { |
| 266 | + throw new Error('You need to specify the target window/tab'); |
| 267 | + } |
| 268 | + return request(id, name, args); |
| 269 | + }]; |
| 270 | + })); |
| 271 | + } |
213 | 272 | };
|
214 | 273 | // -------------------------------------------------------------------------
|
215 | 274 | Object.defineProperty(sysend, 'timeout', {
|
|
244 | 303 | };
|
245 | 304 | })();
|
246 | 305 | // -------------------------------------------------------------------------
|
| 306 | + function is_promise(obj) { |
| 307 | + return obj && typeof object == 'object' && |
| 308 | + typeof object.then === 'function'; |
| 309 | + } |
| 310 | + // ------------------------------------------------------------------------- |
| 311 | + function unpromise(obj, callback, error = null) { |
| 312 | + if (is_promise(obj)) { |
| 313 | + const ret = obj.then(callback); |
| 314 | + if (error === null) { |
| 315 | + return ret; |
| 316 | + } else { |
| 317 | + return ret.catch(error); |
| 318 | + } |
| 319 | + } else { |
| 320 | + return callback(obj); |
| 321 | + } |
| 322 | + } |
| 323 | + // ------------------------------------------------------------------------- |
247 | 324 | function delay(time) {
|
248 | 325 | return function() {
|
249 | 326 | return new Promise(function(resolve) {
|
|
345 | 422 | });
|
346 | 423 | }
|
347 | 424 | // -------------------------------------------------------------------------
|
348 |
| - function trigger(arr) { |
349 |
| - var args = [].slice.call(arguments, 1); |
| 425 | + function trigger(arr, ...args) { |
350 | 426 | arr.forEach(function(fn) {
|
351 | 427 | fn.apply(null, args);
|
352 | 428 | });
|
|
0 commit comments