Comparing version 1.15.0 to 1.16.0
{ | ||
"name": "sysend", | ||
"version": "1.15.0", | ||
"version": "1.16.0", | ||
"description": "Web application synchronization between different tabs", | ||
@@ -5,0 +5,0 @@ "main": "sysend.js", |
@@ -5,4 +5,4 @@ <p align="center"> | ||
[![npm](https://img.shields.io/badge/npm-1.15.0-blue.svg)](https://www.npmjs.com/package/sysend) | ||
![bower](https://img.shields.io/badge/bower-1.15.0-yellow.svg) | ||
[![npm](https://img.shields.io/badge/npm-1.16.0-blue.svg)](https://www.npmjs.com/package/sysend) | ||
![bower](https://img.shields.io/badge/bower-1.16.0-yellow.svg) | ||
![downloads](https://img.shields.io/npm/dt/sysend.svg) | ||
@@ -109,2 +109,51 @@ [![jsdelivr](https://img.shields.io/jsdelivr/npm/hm/sysend)](https://www.jsdelivr.com/package/npm/sysend) | ||
```javascript | ||
let list = []; | ||
sysend.track('open', data => { | ||
if (data.id !== sysend.id) { | ||
list.push(data); | ||
populate_list(list); | ||
} | ||
}); | ||
sysend.track('close', data => { | ||
list = list.filter(tab => data.id !== tab.id); | ||
populate_list(list); | ||
}); | ||
sysend.track('ready', () => { | ||
sysend.list().then(tabs => { | ||
list = tabs; | ||
populate_list(list); | ||
}); | ||
}); | ||
function populate_list() { | ||
select.innerHTML = ''; | ||
list.forEach(tab => { | ||
const option = document.createElement('option'); | ||
option.value = tab.id; | ||
option.innerText = tab.id; | ||
select.appendChild(option); | ||
}); | ||
} | ||
``` | ||
In version 1.16.0 this code was abstracted into: | ||
```javascript | ||
sysend.track('update', (list) => { | ||
populate_list(list); | ||
}); | ||
``` | ||
This can be simplified with point free style: | ||
```javascript | ||
sysend.track('update', populate_list); | ||
``` | ||
### RPC mechanism | ||
In version 1.15.0 new API was added called `rpc()` (build on top of tracking mechanism) that allow to use RPC (Remote Procedure Call) between open windows/tabs. | ||
@@ -140,8 +189,2 @@ | ||
### Security protection | ||
Since version 1.10.0 as a security mesure Cross-Domain communication has been limited to only those domains that are allowed. | ||
To allow domain to listen to sysend communication you need to specify channel inside iframe. You need add your origins to the | ||
`sysend.channel()` function (origin is combination of protocol domain and optional port). | ||
### Serialization | ||
@@ -172,2 +215,9 @@ | ||
### Security protection | ||
Since version 1.10.0 as a security mesure Cross-Domain communication has been limited to only those domains that are allowed. | ||
To allow domain to listen to sysend communication you need to specify channel inside iframe. You need add your origins to the | ||
`sysend.channel()` function (origin is combination of protocol domain and optional port). | ||
## Demos | ||
@@ -196,4 +246,4 @@ | ||
| `list()` | returns a Promise of objects `{id:<UUID>, primary}` for other windows, you can use those to send a message with `post()` | NA | 1.6.0 | | ||
| `track(event, callback)` | track inter window communication events | event - any of the strings: `"open"`, `"close"`, `"primary"`, <br>`"secondary"`, `"message"`<br>callback - different function depend on the event:<br>* `"message"` - `{data, origin}` - where data is anything the `post()` sends, and origin is `id` of the sender.<br>* `"open"` - `{count, primary, id}` when new window/tab is opened<br>* `"close"` - `{count, primary, id, self}` when window/tab is closed<br>* `"primary"` and `"secondary"` function has no arguments and is called when window/tab become secondary or primary.<br>* `"ready"` - event when tracking is ready. | 1.6.0 except `ready` - 1.10.0 | | ||
| `untrack(event [,callback])` | remove single event listener all listeners for a given event | event - any of the strings `'open'`, `'close'`, `'primary'`, `'secondary'`, or `'message'`. | 1.6.0 | | ||
| `track(event, callback)` | track inter window communication events | event - any of the strings: `"open"`, `"close"`, `"primary"`, <br>`"secondary"`, `"message"`, `"update"`<br>callback - different function depend on the event:<br>* `"message"` - `{data, origin}` - where data is anything the `post()` sends, and origin is `id` of the sender.<br>* `"open"` - `{count, primary, id}` when new window/tab is opened<br>* `"close"` - `{count, primary, id, self}` when window/tab is closed<br>* `"primary"` and `"secondary"` function has no arguments and is called when window/tab become secondary or primary.<br>* `"ready"` - event when tracking is ready. | 1.6.0 except `ready` - 1.10.0 and `update` - 1.16.0 | | ||
| `untrack(event [,callback])` | remove single event listener all listeners for a given event | event - any of the strings `'open'`, `'close'`, `'primary'`, `'secondary'`, `'message'`, or `'update'`. | 1.6.0 | | ||
| `isPrimary()` | function returns true if window is primary (first open or last that remain) | NA | 1.6.0 | | ||
@@ -200,0 +250,0 @@ | `channel()` | function restrict cross domain communication to only allowed domains. You need to call this function on proxy iframe to limit number of domains (origins) that can listen and send events. | any number of origins (e.g. 'http://localhost:8080' or 'https://jcubic.github.io') you can also use valid URL. | 1.10.0 | |
/**@license | ||
* sysend.js - send messages between browser windows/tabs version 1.15.0 | ||
* sysend.js - send messages between browser windows/tabs version 1.16.0 | ||
* | ||
@@ -8,20 +8,21 @@ * Copyright (C) 2014-2023 Jakub T. Jankiewicz <https://jcubic.pl/me> | ||
*/ | ||
type callback = (message: any, event: string) => void; | ||
type callback = (message: unknown, event: string) => void; | ||
interface Sysend { | ||
id: string; | ||
broadcast(event: string, data?: any): void; | ||
emit(event: string, data?: any): void; | ||
broadcast(event: string, data?: unknown): void; | ||
emit(event: string, data?: unknown): void; | ||
on(event: string, callback: callback): void; | ||
off(event: string, callback?: callback): void; | ||
proxy(...args: string[]): void; | ||
serializer(to: (data: any) => string, from: (data: string) => any): void; | ||
serializer(to: (data: unknown) => string, from: (data: string) => unknown): void; | ||
track(event: 'open', callback: (data: {id: string, count: number, primary: boolean}) => void): void; | ||
track(event: 'close', callback: (data: {id: string, count: number, primary: boolean, self: boolean}) => void): void; | ||
track(event: 'primary', callback: () => void): void; | ||
track(event: 'message', callback: (payload: {data: any, origin: string}) => void): void; | ||
track(event: 'message', callback: (payload: {data: unknown, origin: string}) => void): void; | ||
track(event: 'secondary', callback: () => void): void; | ||
untrack(event: 'open' | 'close' | 'primary' | 'secondary' | 'message', fn?: (input?: any) => void): void; | ||
track(event: 'update', callback: (payload: Array<{ id: string, primary: boolean }>) => void): void; | ||
untrack(event: 'open' | 'close' | 'primary' | 'secondary' | 'message' | 'update', fn?: (input?: unknown) => void): void; | ||
list(): Promise<Array<{ id: string, primary: boolean }>>; | ||
post(target: string, data?: any): void; | ||
post(target: string, data?: unknown): void; | ||
channel(...domains: string[]): void; | ||
@@ -28,0 +29,0 @@ isPrimary(): boolean; |
104
sysend.js
/**@license | ||
* sysend.js - send messages between browser windows/tabs version 1.15.0 | ||
* sysend.js - send messages between browser windows/tabs version 1.16.0 | ||
* | ||
@@ -24,3 +24,3 @@ * Copyright (C) 2014-2023 Jakub T. Jankiewicz <https://jcubic.pl/me> | ||
var uniq_prefix = '___sysend___'; | ||
var prefix_re = new RegExp(uniq_prefix); | ||
var prefix_re = new RegExp('^' + uniq_prefix); | ||
var random_value = Math.random(); | ||
@@ -57,3 +57,4 @@ var serializer = {}; | ||
visbility: [], | ||
ready: [] | ||
ready: [], | ||
update: [] | ||
}; | ||
@@ -143,3 +144,3 @@ var events = Object.keys(handlers); | ||
}, | ||
off: function(event, fn) { | ||
off: function(event, fn, internal = false) { | ||
if (callbacks[event]) { | ||
@@ -152,3 +153,3 @@ if (fn) { | ||
} | ||
} else { | ||
} else if (internal && is_internal(event) || !internal) { | ||
callbacks[event] = []; | ||
@@ -159,3 +160,6 @@ } | ||
}, | ||
track: function(event, fn) { | ||
track: function(event, fn, internal = false) { | ||
if (internal) { | ||
fn[Symbol.for(uniq_prefix)] = true; | ||
} | ||
if (events.includes(event)) { | ||
@@ -166,6 +170,12 @@ handlers[event].push(fn); | ||
}, | ||
untrack: function(event, fn) { | ||
untrack: function(event, fn, internal = false) { | ||
if (events.includes(event) && handlers[event].length) { | ||
if (fn === undefined) { | ||
handlers[event] = []; | ||
if (internal) { | ||
handlers[event] = []; | ||
} else { | ||
handlers[event] = handlers[event].filter(fn => { | ||
return !fn[Symbol.for(uniq_prefix)]; | ||
}); | ||
} | ||
} else { | ||
@@ -180,3 +190,3 @@ handlers[event] = handlers[event].filter(function(handler) { | ||
post: function(target, data) { | ||
return sysend.broadcast('__message__', { | ||
return sysend.broadcast(make_internal('__message__'), { | ||
target: target, | ||
@@ -193,3 +203,3 @@ data: data, | ||
const ids = []; | ||
sysend.on('__window_ack__', function(data) { | ||
sysend.on(make_internal('__window_ack__'), function(data) { | ||
if (data.origin.target === target_id && data.origin.id === id) { | ||
@@ -202,3 +212,3 @@ ids.push({ | ||
}); | ||
sysend.broadcast('__window__', { id: marker }); | ||
sysend.broadcast(make_internal('__window__'), { id: marker }); | ||
timer().then(function() { | ||
@@ -245,3 +255,3 @@ resolve(ids); | ||
} | ||
}); | ||
}, true); | ||
sysend.post(id, { method, id: req_id, type: req, args }); | ||
@@ -273,3 +283,3 @@ const timer = setTimeout(() => { | ||
} | ||
}); | ||
}, true); | ||
const error_msg = 'You need to specify the target window/tab'; | ||
@@ -397,6 +407,14 @@ return Object.fromEntries(Object.keys(object).map(name => { | ||
// ------------------------------------------------------------------------- | ||
function make_internal(name) { | ||
return uniq_prefix + name; | ||
} | ||
// ------------------------------------------------------------------------- | ||
function is_internal(name) { | ||
return name.match(prefix_re); | ||
} | ||
// ------------------------------------------------------------------------- | ||
// :: valid sysend message | ||
// ------------------------------------------------------------------------- | ||
function is_sysend_post_message(e) { | ||
return typeof e.data === 'string' && e.data.match(prefix_re); | ||
return typeof e.data === 'string' && is_internal(e.data); | ||
} | ||
@@ -446,3 +464,3 @@ // ------------------------------------------------------------------------- | ||
function get(key) { | ||
return localStorage.getItem(uniq_prefix + key); | ||
return localStorage.getItem(make_internal(key)); | ||
} | ||
@@ -453,3 +471,3 @@ // ------------------------------------------------------------------------- | ||
if (id == 0) { | ||
localStorage.setItem(uniq_prefix + key, random_value); | ||
localStorage.setItem(make_internal(key), random_value); | ||
} | ||
@@ -572,3 +590,3 @@ localStorage.setItem(uniq_prefix + key, value); | ||
trigger(handlers.primary); | ||
sysend.emit('__primary__'); | ||
sysend.emit(make_internal('__primary__')); | ||
} | ||
@@ -587,2 +605,5 @@ // ------------------------------------------------------------------------- | ||
} | ||
// ------------------------------------------------------------------------- | ||
setup_update_tracking(); | ||
// ------------------------------------------------------------------------- | ||
function setup_ls() { | ||
@@ -615,2 +636,29 @@ // we need to clean up localStorage if broadcast called on unload | ||
// ------------------------------------------------------------------------- | ||
function setup_update_tracking() { | ||
let list = []; | ||
function update() { | ||
trigger(handlers.update, list); | ||
} | ||
sysend.track('open', data => { | ||
if (data.id !== sysend.id) { | ||
list.push(data); | ||
update(); | ||
} | ||
}, true); | ||
sysend.track('close', data => { | ||
list = list.filter(tab => data.id !== tab.id); | ||
update(); | ||
}, true); | ||
sysend.track('ready', () => { | ||
sysend.list().then(tabs => { | ||
list = tabs; | ||
update(); | ||
}); | ||
}, true); | ||
} | ||
// ------------------------------------------------------------------------- | ||
function init() { | ||
@@ -669,13 +717,13 @@ if (typeof window.BroadcastChannel === 'function') { | ||
} | ||
}); | ||
}, true); | ||
sysend.on('__primary__', function() { | ||
sysend.on(make_internal('__primary__'), function() { | ||
has_primary = true; | ||
}); | ||
sysend.on('__open__', function(data) { | ||
sysend.on(make_internal('__open__'), function(data) { | ||
var id = data.id; | ||
target_count++; | ||
if (primary) { | ||
sysend.broadcast('__ack__'); | ||
sysend.broadcast(make_internal('__ack__')); | ||
} | ||
@@ -692,3 +740,3 @@ trigger(handlers.open, { | ||
sysend.on('__ack__', function() { | ||
sysend.on(make_internal('__ack__'), function() { | ||
if (!primary) { | ||
@@ -699,3 +747,3 @@ trigger(handlers.secondary); | ||
sysend.on('__close__', function(data) { | ||
sysend.on(make_internal('__close__'), function(data) { | ||
--target_count; | ||
@@ -720,4 +768,4 @@ var last = target_count === 1; | ||
sysend.on('__window__', function(data) { | ||
sysend.broadcast('__window_ack__', { | ||
sysend.on(make_internal('__window__'), function(data) { | ||
sysend.broadcast(make_internal('__window_ack__'), { | ||
id: target_id, | ||
@@ -729,3 +777,3 @@ origin: data.id, | ||
sysend.on('__message__', function(data) { | ||
sysend.on(make_internal('__message__'), function(data) { | ||
if (data.target === 'primary' && primary) { | ||
@@ -739,3 +787,3 @@ trigger(handlers.message, data); | ||
addEventListener('beforeunload', function() { | ||
sysend.emit('__close__', { id: target_id, wasPrimary: primary }); | ||
sysend.emit(make_internal('__close__'), { id: target_id, wasPrimary: primary }); | ||
}, { capture: true }); | ||
@@ -753,3 +801,3 @@ | ||
} | ||
sysend.emit('__open__', { | ||
sysend.emit(make_internal('__open__'), { | ||
id: target_id, | ||
@@ -756,0 +804,0 @@ primary: primary |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
46666
805
275