@player-ui/pubsub-plugin 0.4.0-next.1 → 0.4.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +144 -14
- package/dist/index.d.ts +27 -5
- package/dist/index.esm.js +142 -9
- package/dist/pubsub-plugin.dev.js +284 -0
- package/dist/pubsub-plugin.prod.js +1 -0
- package/package.json +13 -4
- package/src/handler.ts +41 -0
- package/src/index.ts +2 -1
- package/src/plugin.ts +102 -0
- package/src/pubsub.ts +149 -53
- package/src/utils.ts +17 -0
package/dist/index.cjs.js
CHANGED
|
@@ -2,11 +2,99 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
function splitEvent(event) {
|
|
6
|
+
return event.split(".").reduce((prev, curr, index) => {
|
|
7
|
+
if (index === 0) {
|
|
8
|
+
return [curr];
|
|
9
|
+
}
|
|
10
|
+
return [...prev, `${prev[index - 1]}.${curr}`];
|
|
11
|
+
}, []);
|
|
12
|
+
}
|
|
13
|
+
let count = 1;
|
|
14
|
+
class TinyPubSub {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.events = new Map();
|
|
17
|
+
this.tokens = new Map();
|
|
18
|
+
}
|
|
19
|
+
publish(event, ...args) {
|
|
20
|
+
if (typeof event !== "string") {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (event.includes(".")) {
|
|
24
|
+
const eventKeys = splitEvent(event);
|
|
25
|
+
eventKeys.forEach((key) => {
|
|
26
|
+
this.deliver(key, event, ...args);
|
|
27
|
+
});
|
|
28
|
+
} else {
|
|
29
|
+
this.deliver(event, event, ...args);
|
|
30
|
+
}
|
|
31
|
+
this.deliver("*", event, ...args);
|
|
32
|
+
}
|
|
33
|
+
subscribe(event, handler) {
|
|
34
|
+
const uuid = `uuid_${++count}`;
|
|
35
|
+
if (typeof event === "string") {
|
|
36
|
+
if (!this.events.has(event)) {
|
|
37
|
+
this.events.set(event, new Map());
|
|
38
|
+
}
|
|
39
|
+
const handlers = this.events.get(event);
|
|
40
|
+
handlers.set(uuid, handler);
|
|
41
|
+
this.tokens.set(uuid, event);
|
|
42
|
+
}
|
|
43
|
+
return uuid;
|
|
44
|
+
}
|
|
45
|
+
unsubscribe(value) {
|
|
46
|
+
if (typeof value === "string" && value.startsWith("uuid")) {
|
|
47
|
+
const path = this.tokens.get(value);
|
|
48
|
+
if (typeof path === "undefined") {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const innerPath = this.events.get(path);
|
|
52
|
+
innerPath == null ? void 0 : innerPath.delete(value);
|
|
53
|
+
this.tokens.delete(value);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === "string") {
|
|
57
|
+
for (const key of this.events.keys()) {
|
|
58
|
+
if (key.indexOf(value) === 0) {
|
|
59
|
+
const tokens = this.events.get(key);
|
|
60
|
+
if (tokens && tokens.size) {
|
|
61
|
+
for (const token of tokens.keys()) {
|
|
62
|
+
this.tokens.delete(token);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
this.events.delete(key);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
count(event) {
|
|
71
|
+
let counter = 0;
|
|
72
|
+
if (typeof event === "undefined") {
|
|
73
|
+
for (const handlers2 of this.events.values()) {
|
|
74
|
+
counter += handlers2.size;
|
|
75
|
+
}
|
|
76
|
+
return counter;
|
|
77
|
+
}
|
|
78
|
+
const handlers = this.events.get(event);
|
|
79
|
+
if (handlers == null ? void 0 : handlers.size) {
|
|
80
|
+
return handlers.size;
|
|
81
|
+
}
|
|
82
|
+
return counter;
|
|
83
|
+
}
|
|
84
|
+
clear() {
|
|
85
|
+
this.events.clear();
|
|
86
|
+
this.tokens.clear();
|
|
87
|
+
}
|
|
88
|
+
deliver(path, event, ...args) {
|
|
89
|
+
const handlers = this.events.get(path);
|
|
90
|
+
if (handlers && handlers.size) {
|
|
91
|
+
for (const handler of handlers.values()) {
|
|
92
|
+
handler(event, ...args);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const pubsub = new TinyPubSub();
|
|
10
98
|
|
|
11
99
|
const PubSubPluginSymbol = Symbol.for("PubSubPlugin");
|
|
12
100
|
|
|
@@ -19,26 +107,68 @@ const _PubSubPlugin = class {
|
|
|
19
107
|
}
|
|
20
108
|
apply(player) {
|
|
21
109
|
player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
|
|
22
|
-
expEvaluator.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
110
|
+
const existingExpression = expEvaluator.operators.expressions.get(this.expressionName);
|
|
111
|
+
if (existingExpression) {
|
|
112
|
+
player.logger.warn(`[PubSubPlugin] expression ${this.expressionName} is already registered.`);
|
|
113
|
+
} else {
|
|
114
|
+
expEvaluator.addExpressionFunction(this.expressionName, (_ctx, event, ...args) => {
|
|
115
|
+
if (typeof event === "string") {
|
|
116
|
+
this.publish(event, ...args);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
player.hooks.onEnd.tap(this.name, () => {
|
|
122
|
+
this.clear();
|
|
27
123
|
});
|
|
28
124
|
}
|
|
29
|
-
publish(event,
|
|
30
|
-
|
|
125
|
+
publish(event, ...args) {
|
|
126
|
+
pubsub.publish(event, ...args);
|
|
31
127
|
}
|
|
32
128
|
subscribe(event, handler) {
|
|
33
|
-
return
|
|
129
|
+
return pubsub.subscribe(event, handler);
|
|
34
130
|
}
|
|
35
131
|
unsubscribe(token) {
|
|
36
|
-
|
|
132
|
+
pubsub.unsubscribe(token);
|
|
133
|
+
}
|
|
134
|
+
clear() {
|
|
135
|
+
pubsub.clear();
|
|
37
136
|
}
|
|
38
137
|
};
|
|
39
138
|
let PubSubPlugin = _PubSubPlugin;
|
|
40
139
|
PubSubPlugin.Symbol = PubSubPluginSymbol;
|
|
41
140
|
|
|
141
|
+
function getPubSubPlugin(player) {
|
|
142
|
+
const existing = player.findPlugin(PubSubPluginSymbol);
|
|
143
|
+
const plugin = existing || new PubSubPlugin();
|
|
144
|
+
if (!existing) {
|
|
145
|
+
player.registerPlugin(plugin);
|
|
146
|
+
}
|
|
147
|
+
return plugin;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
class PubSubHandlerPlugin {
|
|
151
|
+
constructor(subscriptions) {
|
|
152
|
+
this.name = "pubsub-handler";
|
|
153
|
+
this.subscriptions = subscriptions;
|
|
154
|
+
}
|
|
155
|
+
apply(player) {
|
|
156
|
+
const pubsub = getPubSubPlugin(player);
|
|
157
|
+
player.hooks.onStart.tap(this.name, () => {
|
|
158
|
+
this.subscriptions.forEach((handler, key) => {
|
|
159
|
+
pubsub.subscribe(key, (_, ...args) => {
|
|
160
|
+
const state = player.getState();
|
|
161
|
+
if (state.status === "in-progress") {
|
|
162
|
+
return handler(state, ...args);
|
|
163
|
+
}
|
|
164
|
+
player.logger.info(`[PubSubHandlerPlugin] subscriber for ${key} was called when player was not in-progress`);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
exports.PubSubHandlerPlugin = PubSubHandlerPlugin;
|
|
42
172
|
exports.PubSubPlugin = PubSubPlugin;
|
|
43
173
|
exports.PubSubPluginSymbol = PubSubPluginSymbol;
|
|
44
174
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import { PlayerPlugin, Player } from '@player-ui/player';
|
|
1
|
+
import { PlayerPlugin, Player, InProgressState } from '@player-ui/player';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Based off the pubsub-js library and rewritten to match the same used APIs but modified so that
|
|
5
|
+
* multiple arguments could be passed into the publish and subscription handlers.
|
|
6
|
+
*/
|
|
7
|
+
declare type SubscribeHandler<T extends string, A extends unknown[]> = (type: T, ...args: A) => void;
|
|
2
8
|
|
|
3
9
|
interface PubSubConfig {
|
|
4
10
|
/** A custom expression name to register */
|
|
5
11
|
expressionName: string;
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
8
|
-
* The PubSubPlugin is a great way to enable your
|
|
14
|
+
* The PubSubPlugin is a great way to enable your FRF content to publish events back to your app
|
|
9
15
|
* It injects a publish() function into the expression language, and will forward all events back to any subscribers.
|
|
10
16
|
*
|
|
11
17
|
* Published/Subscribed events support a hierarchy:
|
|
@@ -26,7 +32,7 @@ declare class PubSubPlugin implements PlayerPlugin {
|
|
|
26
32
|
* @param event - The name of the event to publish. Can take sub-topics like: foo.bar
|
|
27
33
|
* @param data - Any additional data to attach to the event
|
|
28
34
|
*/
|
|
29
|
-
publish(event: string,
|
|
35
|
+
publish(event: string, ...args: unknown[]): void;
|
|
30
36
|
/**
|
|
31
37
|
* Subscribe to an event with the given name. The handler will get called for any published event
|
|
32
38
|
*
|
|
@@ -34,15 +40,31 @@ declare class PubSubPlugin implements PlayerPlugin {
|
|
|
34
40
|
* @param handler - A function to be called when the event is triggered
|
|
35
41
|
* @returns A token to be used to unsubscribe from the event
|
|
36
42
|
*/
|
|
37
|
-
subscribe
|
|
43
|
+
subscribe<T extends string, A extends unknown[]>(event: T, handler: SubscribeHandler<T, A>): string;
|
|
38
44
|
/**
|
|
39
45
|
* Remove any subscriptions using the given token
|
|
40
46
|
*
|
|
41
47
|
* @param token - A token from a `subscribe` call
|
|
42
48
|
*/
|
|
43
49
|
unsubscribe(token: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Remove all subscriptions
|
|
52
|
+
*/
|
|
53
|
+
clear(): void;
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
declare const PubSubPluginSymbol: unique symbol;
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
declare type PubSubHandler<T extends unknown[]> = (context: InProgressState, ...args: T) => void;
|
|
59
|
+
declare type SubscriptionMap = Map<string, PubSubHandler<any>>;
|
|
60
|
+
/**
|
|
61
|
+
* Plugin to easily add subscribers to the PubSubPlugin
|
|
62
|
+
*/
|
|
63
|
+
declare class PubSubHandlerPlugin implements PlayerPlugin {
|
|
64
|
+
name: string;
|
|
65
|
+
private subscriptions;
|
|
66
|
+
constructor(subscriptions: SubscriptionMap);
|
|
67
|
+
apply(player: Player): void;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { PubSubConfig, PubSubHandler, PubSubHandlerPlugin, PubSubPlugin, PubSubPluginSymbol, SubscriptionMap };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,96 @@
|
|
|
1
|
-
|
|
1
|
+
function splitEvent(event) {
|
|
2
|
+
return event.split(".").reduce((prev, curr, index) => {
|
|
3
|
+
if (index === 0) {
|
|
4
|
+
return [curr];
|
|
5
|
+
}
|
|
6
|
+
return [...prev, `${prev[index - 1]}.${curr}`];
|
|
7
|
+
}, []);
|
|
8
|
+
}
|
|
9
|
+
let count = 1;
|
|
10
|
+
class TinyPubSub {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.events = new Map();
|
|
13
|
+
this.tokens = new Map();
|
|
14
|
+
}
|
|
15
|
+
publish(event, ...args) {
|
|
16
|
+
if (typeof event !== "string") {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (event.includes(".")) {
|
|
20
|
+
const eventKeys = splitEvent(event);
|
|
21
|
+
eventKeys.forEach((key) => {
|
|
22
|
+
this.deliver(key, event, ...args);
|
|
23
|
+
});
|
|
24
|
+
} else {
|
|
25
|
+
this.deliver(event, event, ...args);
|
|
26
|
+
}
|
|
27
|
+
this.deliver("*", event, ...args);
|
|
28
|
+
}
|
|
29
|
+
subscribe(event, handler) {
|
|
30
|
+
const uuid = `uuid_${++count}`;
|
|
31
|
+
if (typeof event === "string") {
|
|
32
|
+
if (!this.events.has(event)) {
|
|
33
|
+
this.events.set(event, new Map());
|
|
34
|
+
}
|
|
35
|
+
const handlers = this.events.get(event);
|
|
36
|
+
handlers.set(uuid, handler);
|
|
37
|
+
this.tokens.set(uuid, event);
|
|
38
|
+
}
|
|
39
|
+
return uuid;
|
|
40
|
+
}
|
|
41
|
+
unsubscribe(value) {
|
|
42
|
+
if (typeof value === "string" && value.startsWith("uuid")) {
|
|
43
|
+
const path = this.tokens.get(value);
|
|
44
|
+
if (typeof path === "undefined") {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const innerPath = this.events.get(path);
|
|
48
|
+
innerPath == null ? void 0 : innerPath.delete(value);
|
|
49
|
+
this.tokens.delete(value);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (typeof value === "string") {
|
|
53
|
+
for (const key of this.events.keys()) {
|
|
54
|
+
if (key.indexOf(value) === 0) {
|
|
55
|
+
const tokens = this.events.get(key);
|
|
56
|
+
if (tokens && tokens.size) {
|
|
57
|
+
for (const token of tokens.keys()) {
|
|
58
|
+
this.tokens.delete(token);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
this.events.delete(key);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
count(event) {
|
|
67
|
+
let counter = 0;
|
|
68
|
+
if (typeof event === "undefined") {
|
|
69
|
+
for (const handlers2 of this.events.values()) {
|
|
70
|
+
counter += handlers2.size;
|
|
71
|
+
}
|
|
72
|
+
return counter;
|
|
73
|
+
}
|
|
74
|
+
const handlers = this.events.get(event);
|
|
75
|
+
if (handlers == null ? void 0 : handlers.size) {
|
|
76
|
+
return handlers.size;
|
|
77
|
+
}
|
|
78
|
+
return counter;
|
|
79
|
+
}
|
|
80
|
+
clear() {
|
|
81
|
+
this.events.clear();
|
|
82
|
+
this.tokens.clear();
|
|
83
|
+
}
|
|
84
|
+
deliver(path, event, ...args) {
|
|
85
|
+
const handlers = this.events.get(path);
|
|
86
|
+
if (handlers && handlers.size) {
|
|
87
|
+
for (const handler of handlers.values()) {
|
|
88
|
+
handler(event, ...args);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const pubsub = new TinyPubSub();
|
|
2
94
|
|
|
3
95
|
const PubSubPluginSymbol = Symbol.for("PubSubPlugin");
|
|
4
96
|
|
|
@@ -11,15 +103,23 @@ const _PubSubPlugin = class {
|
|
|
11
103
|
}
|
|
12
104
|
apply(player) {
|
|
13
105
|
player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
|
|
14
|
-
expEvaluator.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
106
|
+
const existingExpression = expEvaluator.operators.expressions.get(this.expressionName);
|
|
107
|
+
if (existingExpression) {
|
|
108
|
+
player.logger.warn(`[PubSubPlugin] expression ${this.expressionName} is already registered.`);
|
|
109
|
+
} else {
|
|
110
|
+
expEvaluator.addExpressionFunction(this.expressionName, (_ctx, event, ...args) => {
|
|
111
|
+
if (typeof event === "string") {
|
|
112
|
+
this.publish(event, ...args);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
player.hooks.onEnd.tap(this.name, () => {
|
|
118
|
+
this.clear();
|
|
19
119
|
});
|
|
20
120
|
}
|
|
21
|
-
publish(event,
|
|
22
|
-
pubsub.
|
|
121
|
+
publish(event, ...args) {
|
|
122
|
+
pubsub.publish(event, ...args);
|
|
23
123
|
}
|
|
24
124
|
subscribe(event, handler) {
|
|
25
125
|
return pubsub.subscribe(event, handler);
|
|
@@ -27,9 +127,42 @@ const _PubSubPlugin = class {
|
|
|
27
127
|
unsubscribe(token) {
|
|
28
128
|
pubsub.unsubscribe(token);
|
|
29
129
|
}
|
|
130
|
+
clear() {
|
|
131
|
+
pubsub.clear();
|
|
132
|
+
}
|
|
30
133
|
};
|
|
31
134
|
let PubSubPlugin = _PubSubPlugin;
|
|
32
135
|
PubSubPlugin.Symbol = PubSubPluginSymbol;
|
|
33
136
|
|
|
34
|
-
|
|
137
|
+
function getPubSubPlugin(player) {
|
|
138
|
+
const existing = player.findPlugin(PubSubPluginSymbol);
|
|
139
|
+
const plugin = existing || new PubSubPlugin();
|
|
140
|
+
if (!existing) {
|
|
141
|
+
player.registerPlugin(plugin);
|
|
142
|
+
}
|
|
143
|
+
return plugin;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
class PubSubHandlerPlugin {
|
|
147
|
+
constructor(subscriptions) {
|
|
148
|
+
this.name = "pubsub-handler";
|
|
149
|
+
this.subscriptions = subscriptions;
|
|
150
|
+
}
|
|
151
|
+
apply(player) {
|
|
152
|
+
const pubsub = getPubSubPlugin(player);
|
|
153
|
+
player.hooks.onStart.tap(this.name, () => {
|
|
154
|
+
this.subscriptions.forEach((handler, key) => {
|
|
155
|
+
pubsub.subscribe(key, (_, ...args) => {
|
|
156
|
+
const state = player.getState();
|
|
157
|
+
if (state.status === "in-progress") {
|
|
158
|
+
return handler(state, ...args);
|
|
159
|
+
}
|
|
160
|
+
player.logger.info(`[PubSubHandlerPlugin] subscriber for ${key} was called when player was not in-progress`);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export { PubSubHandlerPlugin, PubSubPlugin, PubSubPluginSymbol };
|
|
35
168
|
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
(function webpackUniversalModuleDefinition(root, factory) {
|
|
2
|
+
if(typeof exports === 'object' && typeof module === 'object')
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
else if(typeof define === 'function' && define.amd)
|
|
5
|
+
define([], factory);
|
|
6
|
+
else if(typeof exports === 'object')
|
|
7
|
+
exports["PubSubPlugin"] = factory();
|
|
8
|
+
else
|
|
9
|
+
root["PubSubPlugin"] = factory();
|
|
10
|
+
})(this, function() {
|
|
11
|
+
return /******/ (function(modules) { // webpackBootstrap
|
|
12
|
+
/******/ // The module cache
|
|
13
|
+
/******/ var installedModules = {};
|
|
14
|
+
/******/
|
|
15
|
+
/******/ // The require function
|
|
16
|
+
/******/ function __webpack_require__(moduleId) {
|
|
17
|
+
/******/
|
|
18
|
+
/******/ // Check if module is in cache
|
|
19
|
+
/******/ if(installedModules[moduleId]) {
|
|
20
|
+
/******/ return installedModules[moduleId].exports;
|
|
21
|
+
/******/ }
|
|
22
|
+
/******/ // Create a new module (and put it into the cache)
|
|
23
|
+
/******/ var module = installedModules[moduleId] = {
|
|
24
|
+
/******/ i: moduleId,
|
|
25
|
+
/******/ l: false,
|
|
26
|
+
/******/ exports: {}
|
|
27
|
+
/******/ };
|
|
28
|
+
/******/
|
|
29
|
+
/******/ // Execute the module function
|
|
30
|
+
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
31
|
+
/******/
|
|
32
|
+
/******/ // Flag the module as loaded
|
|
33
|
+
/******/ module.l = true;
|
|
34
|
+
/******/
|
|
35
|
+
/******/ // Return the exports of the module
|
|
36
|
+
/******/ return module.exports;
|
|
37
|
+
/******/ }
|
|
38
|
+
/******/
|
|
39
|
+
/******/
|
|
40
|
+
/******/ // expose the modules object (__webpack_modules__)
|
|
41
|
+
/******/ __webpack_require__.m = modules;
|
|
42
|
+
/******/
|
|
43
|
+
/******/ // expose the module cache
|
|
44
|
+
/******/ __webpack_require__.c = installedModules;
|
|
45
|
+
/******/
|
|
46
|
+
/******/ // define getter function for harmony exports
|
|
47
|
+
/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
48
|
+
/******/ if(!__webpack_require__.o(exports, name)) {
|
|
49
|
+
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
50
|
+
/******/ }
|
|
51
|
+
/******/ };
|
|
52
|
+
/******/
|
|
53
|
+
/******/ // define __esModule on exports
|
|
54
|
+
/******/ __webpack_require__.r = function(exports) {
|
|
55
|
+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
56
|
+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
57
|
+
/******/ }
|
|
58
|
+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
59
|
+
/******/ };
|
|
60
|
+
/******/
|
|
61
|
+
/******/ // create a fake namespace object
|
|
62
|
+
/******/ // mode & 1: value is a module id, require it
|
|
63
|
+
/******/ // mode & 2: merge all properties of value into the ns
|
|
64
|
+
/******/ // mode & 4: return value when already ns object
|
|
65
|
+
/******/ // mode & 8|1: behave like require
|
|
66
|
+
/******/ __webpack_require__.t = function(value, mode) {
|
|
67
|
+
/******/ if(mode & 1) value = __webpack_require__(value);
|
|
68
|
+
/******/ if(mode & 8) return value;
|
|
69
|
+
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
|
70
|
+
/******/ var ns = Object.create(null);
|
|
71
|
+
/******/ __webpack_require__.r(ns);
|
|
72
|
+
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
|
73
|
+
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
|
74
|
+
/******/ return ns;
|
|
75
|
+
/******/ };
|
|
76
|
+
/******/
|
|
77
|
+
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
78
|
+
/******/ __webpack_require__.n = function(module) {
|
|
79
|
+
/******/ var getter = module && module.__esModule ?
|
|
80
|
+
/******/ function getDefault() { return module['default']; } :
|
|
81
|
+
/******/ function getModuleExports() { return module; };
|
|
82
|
+
/******/ __webpack_require__.d(getter, 'a', getter);
|
|
83
|
+
/******/ return getter;
|
|
84
|
+
/******/ };
|
|
85
|
+
/******/
|
|
86
|
+
/******/ // Object.prototype.hasOwnProperty.call
|
|
87
|
+
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
88
|
+
/******/
|
|
89
|
+
/******/ // __webpack_public_path__
|
|
90
|
+
/******/ __webpack_require__.p = "";
|
|
91
|
+
/******/
|
|
92
|
+
/******/
|
|
93
|
+
/******/ // Load entry module and return exports
|
|
94
|
+
/******/ return __webpack_require__(__webpack_require__.s = "./bazel-out/k8-fastbuild/bin/plugins/pubsub/core/dist/index.esm.js");
|
|
95
|
+
/******/ })
|
|
96
|
+
/************************************************************************/
|
|
97
|
+
/******/ ({
|
|
98
|
+
|
|
99
|
+
/***/ "./bazel-out/k8-fastbuild/bin/plugins/pubsub/core/dist/index.esm.js":
|
|
100
|
+
/*!**************************************************************************!*\
|
|
101
|
+
!*** ./bazel-out/k8-fastbuild/bin/plugins/pubsub/core/dist/index.esm.js ***!
|
|
102
|
+
\**************************************************************************/
|
|
103
|
+
/*! exports provided: PubSubHandlerPlugin, PubSubPlugin, PubSubPluginSymbol */
|
|
104
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
105
|
+
|
|
106
|
+
"use strict";
|
|
107
|
+
__webpack_require__.r(__webpack_exports__);
|
|
108
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PubSubHandlerPlugin", function() { return PubSubHandlerPlugin; });
|
|
109
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PubSubPlugin", function() { return PubSubPlugin; });
|
|
110
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PubSubPluginSymbol", function() { return PubSubPluginSymbol; });
|
|
111
|
+
function splitEvent(event) {
|
|
112
|
+
return event.split(".").reduce((prev, curr, index) => {
|
|
113
|
+
if (index === 0) {
|
|
114
|
+
return [curr];
|
|
115
|
+
}
|
|
116
|
+
return [...prev, `${prev[index - 1]}.${curr}`];
|
|
117
|
+
}, []);
|
|
118
|
+
}
|
|
119
|
+
let count = 1;
|
|
120
|
+
class TinyPubSub {
|
|
121
|
+
constructor() {
|
|
122
|
+
this.events = new Map();
|
|
123
|
+
this.tokens = new Map();
|
|
124
|
+
}
|
|
125
|
+
publish(event, ...args) {
|
|
126
|
+
if (typeof event !== "string") {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (event.includes(".")) {
|
|
130
|
+
const eventKeys = splitEvent(event);
|
|
131
|
+
eventKeys.forEach((key) => {
|
|
132
|
+
this.deliver(key, event, ...args);
|
|
133
|
+
});
|
|
134
|
+
} else {
|
|
135
|
+
this.deliver(event, event, ...args);
|
|
136
|
+
}
|
|
137
|
+
this.deliver("*", event, ...args);
|
|
138
|
+
}
|
|
139
|
+
subscribe(event, handler) {
|
|
140
|
+
const uuid = `uuid_${++count}`;
|
|
141
|
+
if (typeof event === "string") {
|
|
142
|
+
if (!this.events.has(event)) {
|
|
143
|
+
this.events.set(event, new Map());
|
|
144
|
+
}
|
|
145
|
+
const handlers = this.events.get(event);
|
|
146
|
+
handlers.set(uuid, handler);
|
|
147
|
+
this.tokens.set(uuid, event);
|
|
148
|
+
}
|
|
149
|
+
return uuid;
|
|
150
|
+
}
|
|
151
|
+
unsubscribe(value) {
|
|
152
|
+
if (typeof value === "string" && value.startsWith("uuid")) {
|
|
153
|
+
const path = this.tokens.get(value);
|
|
154
|
+
if (typeof path === "undefined") {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const innerPath = this.events.get(path);
|
|
158
|
+
innerPath == null ? void 0 : innerPath.delete(value);
|
|
159
|
+
this.tokens.delete(value);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (typeof value === "string") {
|
|
163
|
+
for (const key of this.events.keys()) {
|
|
164
|
+
if (key.indexOf(value) === 0) {
|
|
165
|
+
const tokens = this.events.get(key);
|
|
166
|
+
if (tokens && tokens.size) {
|
|
167
|
+
for (const token of tokens.keys()) {
|
|
168
|
+
this.tokens.delete(token);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
this.events.delete(key);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
count(event) {
|
|
177
|
+
let counter = 0;
|
|
178
|
+
if (typeof event === "undefined") {
|
|
179
|
+
for (const handlers2 of this.events.values()) {
|
|
180
|
+
counter += handlers2.size;
|
|
181
|
+
}
|
|
182
|
+
return counter;
|
|
183
|
+
}
|
|
184
|
+
const handlers = this.events.get(event);
|
|
185
|
+
if (handlers == null ? void 0 : handlers.size) {
|
|
186
|
+
return handlers.size;
|
|
187
|
+
}
|
|
188
|
+
return counter;
|
|
189
|
+
}
|
|
190
|
+
clear() {
|
|
191
|
+
this.events.clear();
|
|
192
|
+
this.tokens.clear();
|
|
193
|
+
}
|
|
194
|
+
deliver(path, event, ...args) {
|
|
195
|
+
const handlers = this.events.get(path);
|
|
196
|
+
if (handlers && handlers.size) {
|
|
197
|
+
for (const handler of handlers.values()) {
|
|
198
|
+
handler(event, ...args);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const pubsub = new TinyPubSub();
|
|
204
|
+
|
|
205
|
+
const PubSubPluginSymbol = Symbol.for("PubSubPlugin");
|
|
206
|
+
|
|
207
|
+
const _PubSubPlugin = class {
|
|
208
|
+
constructor(config) {
|
|
209
|
+
this.name = "pub-sub";
|
|
210
|
+
this.symbol = _PubSubPlugin.Symbol;
|
|
211
|
+
var _a;
|
|
212
|
+
this.expressionName = (_a = config == null ? void 0 : config.expressionName) != null ? _a : "publish";
|
|
213
|
+
}
|
|
214
|
+
apply(player) {
|
|
215
|
+
player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
|
|
216
|
+
const existingExpression = expEvaluator.operators.expressions.get(this.expressionName);
|
|
217
|
+
if (existingExpression) {
|
|
218
|
+
player.logger.warn(`[PubSubPlugin] expression ${this.expressionName} is already registered.`);
|
|
219
|
+
} else {
|
|
220
|
+
expEvaluator.addExpressionFunction(this.expressionName, (_ctx, event, ...args) => {
|
|
221
|
+
if (typeof event === "string") {
|
|
222
|
+
this.publish(event, ...args);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
player.hooks.onEnd.tap(this.name, () => {
|
|
228
|
+
this.clear();
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
publish(event, ...args) {
|
|
232
|
+
pubsub.publish(event, ...args);
|
|
233
|
+
}
|
|
234
|
+
subscribe(event, handler) {
|
|
235
|
+
return pubsub.subscribe(event, handler);
|
|
236
|
+
}
|
|
237
|
+
unsubscribe(token) {
|
|
238
|
+
pubsub.unsubscribe(token);
|
|
239
|
+
}
|
|
240
|
+
clear() {
|
|
241
|
+
pubsub.clear();
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
let PubSubPlugin = _PubSubPlugin;
|
|
245
|
+
PubSubPlugin.Symbol = PubSubPluginSymbol;
|
|
246
|
+
|
|
247
|
+
function getPubSubPlugin(player) {
|
|
248
|
+
const existing = player.findPlugin(PubSubPluginSymbol);
|
|
249
|
+
const plugin = existing || new PubSubPlugin();
|
|
250
|
+
if (!existing) {
|
|
251
|
+
player.registerPlugin(plugin);
|
|
252
|
+
}
|
|
253
|
+
return plugin;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
class PubSubHandlerPlugin {
|
|
257
|
+
constructor(subscriptions) {
|
|
258
|
+
this.name = "pubsub-handler";
|
|
259
|
+
this.subscriptions = subscriptions;
|
|
260
|
+
}
|
|
261
|
+
apply(player) {
|
|
262
|
+
const pubsub = getPubSubPlugin(player);
|
|
263
|
+
player.hooks.onStart.tap(this.name, () => {
|
|
264
|
+
this.subscriptions.forEach((handler, key) => {
|
|
265
|
+
pubsub.subscribe(key, (_, ...args) => {
|
|
266
|
+
const state = player.getState();
|
|
267
|
+
if (state.status === "in-progress") {
|
|
268
|
+
return handler(state, ...args);
|
|
269
|
+
}
|
|
270
|
+
player.logger.info(`[PubSubHandlerPlugin] subscriber for ${key} was called when player was not in-progress`);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
//# sourceMappingURL=index.esm.js.map
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
/***/ })
|
|
282
|
+
|
|
283
|
+
/******/ });
|
|
284
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"===typeof exports&&"object"===typeof module?module.exports=t():"function"===typeof define&&define.amd?define([],t):"object"===typeof exports?exports.PubSubPlugin=t():e.PubSubPlugin=t()}(this,(function(){return function(e){var t={};function n(s){if(t[s])return t[s].exports;var r=t[s]={i:s,l:!1,exports:{}};return e[s].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=e,n.c=t,n.d=function(e,t,s){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(n.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(s,r,function(t){return e[t]}.bind(null,r));return s},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t),n.d(t,"PubSubHandlerPlugin",(function(){return l})),n.d(t,"PubSubPlugin",(function(){return u})),n.d(t,"PubSubPluginSymbol",(function(){return i}));let s=1;const r=new class{constructor(){this.events=new Map,this.tokens=new Map}publish(e,...t){if("string"===typeof e){if(e.includes(".")){const n=function(e){return e.split(".").reduce(((e,t,n)=>0===n?[t]:[...e,`${e[n-1]}.${t}`]),[])}(e);n.forEach((n=>{this.deliver(n,e,...t)}))}else this.deliver(e,e,...t);this.deliver("*",e,...t)}}subscribe(e,t){const n="uuid_"+ ++s;if("string"===typeof e){this.events.has(e)||this.events.set(e,new Map);this.events.get(e).set(n,t),this.tokens.set(n,e)}return n}unsubscribe(e){if("string"===typeof e&&e.startsWith("uuid")){const t=this.tokens.get(e);if("undefined"===typeof t)return;const n=this.events.get(t);return null==n||n.delete(e),void this.tokens.delete(e)}if("string"===typeof e)for(const t of this.events.keys())if(0===t.indexOf(e)){const e=this.events.get(t);if(e&&e.size)for(const t of e.keys())this.tokens.delete(t);this.events.delete(t)}}count(e){let t=0;if("undefined"===typeof e){for(const e of this.events.values())t+=e.size;return t}const n=this.events.get(e);return(null==n?void 0:n.size)?n.size:t}clear(){this.events.clear(),this.tokens.clear()}deliver(e,t,...n){const s=this.events.get(e);if(s&&s.size)for(const r of s.values())r(t,...n)}},i=Symbol.for("PubSubPlugin"),o=class{constructor(e){var t;this.name="pub-sub",this.symbol=o.Symbol,this.expressionName=null!=(t=null==e?void 0:e.expressionName)?t:"publish"}apply(e){e.hooks.expressionEvaluator.tap(this.name,(t=>{t.operators.expressions.get(this.expressionName)?e.logger.warn(`[PubSubPlugin] expression ${this.expressionName} is already registered.`):t.addExpressionFunction(this.expressionName,((e,t,...n)=>{"string"===typeof t&&this.publish(t,...n)}))})),e.hooks.onEnd.tap(this.name,(()=>{this.clear()}))}publish(e,...t){r.publish(e,...t)}subscribe(e,t){return r.subscribe(e,t)}unsubscribe(e){r.unsubscribe(e)}clear(){r.clear()}};let u=o;u.Symbol=i;class l{constructor(e){this.name="pubsub-handler",this.subscriptions=e}apply(e){const t=function(e){const t=e.findPlugin(i),n=t||new u;return t||e.registerPlugin(n),n}(e);e.hooks.onStart.tap(this.name,(()=>{this.subscriptions.forEach(((n,s)=>{t.subscribe(s,((t,...r)=>{const i=e.getState();if("in-progress"===i.status)return n(i,...r);e.logger.info(`[PubSubHandlerPlugin] subscriber for ${s} was called when player was not in-progress`)}))}))}))}}}])}));
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@player-ui/pubsub-plugin",
|
|
3
|
-
"version": "0.4.0-next.
|
|
3
|
+
"version": "0.4.0-next.10",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org"
|
|
7
7
|
},
|
|
8
8
|
"peerDependencies": {
|
|
9
|
-
"@player-ui/player": "0.4.0-next.
|
|
9
|
+
"@player-ui/player": "0.4.0-next.10"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"tapable-ts": "^0.2.
|
|
12
|
+
"tapable-ts": "^0.2.3",
|
|
13
13
|
"pubsub-js": "^1.9.3",
|
|
14
14
|
"@types/pubsub-js": "^1.8.3",
|
|
15
15
|
"@babel/runtime": "7.15.4"
|
|
@@ -55,6 +55,15 @@
|
|
|
55
55
|
{
|
|
56
56
|
"name": "Kelly Harrop",
|
|
57
57
|
"url": "https://github.com/kharrop"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "Alejandro Fimbres",
|
|
61
|
+
"url": "https://github.com/lexfm"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "Rafael Campos",
|
|
65
|
+
"url": "https://github.com/rafbcampos"
|
|
58
66
|
}
|
|
59
|
-
]
|
|
67
|
+
],
|
|
68
|
+
"bundle": "./dist/pubsub-plugin.prod.js"
|
|
60
69
|
}
|
package/src/handler.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Player, PlayerPlugin, InProgressState } from '@player-ui/player';
|
|
2
|
+
import { getPubSubPlugin } from './utils';
|
|
3
|
+
|
|
4
|
+
export type PubSubHandler<T extends unknown[]> = (
|
|
5
|
+
context: InProgressState,
|
|
6
|
+
...args: T
|
|
7
|
+
) => void;
|
|
8
|
+
|
|
9
|
+
export type SubscriptionMap = Map<string, PubSubHandler<any>>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Plugin to easily add subscribers to the PubSubPlugin
|
|
13
|
+
*/
|
|
14
|
+
export class PubSubHandlerPlugin implements PlayerPlugin {
|
|
15
|
+
name = 'pubsub-handler';
|
|
16
|
+
private subscriptions: SubscriptionMap;
|
|
17
|
+
|
|
18
|
+
constructor(subscriptions: SubscriptionMap) {
|
|
19
|
+
this.subscriptions = subscriptions;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
apply(player: Player) {
|
|
23
|
+
const pubsub = getPubSubPlugin(player);
|
|
24
|
+
|
|
25
|
+
player.hooks.onStart.tap(this.name, () => {
|
|
26
|
+
this.subscriptions.forEach((handler, key) => {
|
|
27
|
+
pubsub.subscribe(key, (_, ...args) => {
|
|
28
|
+
const state = player.getState();
|
|
29
|
+
|
|
30
|
+
if (state.status === 'in-progress') {
|
|
31
|
+
return handler(state, ...args);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
player.logger.info(
|
|
35
|
+
`[PubSubHandlerPlugin] subscriber for ${key} was called when player was not in-progress`
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/index.ts
CHANGED
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Player,
|
|
3
|
+
PlayerPlugin,
|
|
4
|
+
ExpressionContext,
|
|
5
|
+
} from '@player-ui/player';
|
|
6
|
+
import type { SubscribeHandler } from './pubsub';
|
|
7
|
+
import { pubsub } from './pubsub';
|
|
8
|
+
import { PubSubPluginSymbol } from './symbols';
|
|
9
|
+
|
|
10
|
+
export interface PubSubConfig {
|
|
11
|
+
/** A custom expression name to register */
|
|
12
|
+
expressionName: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The PubSubPlugin is a great way to enable your FRF content to publish events back to your app
|
|
17
|
+
* It injects a publish() function into the expression language, and will forward all events back to any subscribers.
|
|
18
|
+
*
|
|
19
|
+
* Published/Subscribed events support a hierarchy:
|
|
20
|
+
* - publish('foo', 'data') -- will trigger any listeners for 'foo'
|
|
21
|
+
* - publish('foo.bar', 'data') -- will trigger any listeners for 'foo' or 'foo.bar'
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
export class PubSubPlugin implements PlayerPlugin {
|
|
25
|
+
name = 'pub-sub';
|
|
26
|
+
|
|
27
|
+
static Symbol = PubSubPluginSymbol;
|
|
28
|
+
public readonly symbol = PubSubPlugin.Symbol;
|
|
29
|
+
|
|
30
|
+
private expressionName: string;
|
|
31
|
+
|
|
32
|
+
constructor(config?: PubSubConfig) {
|
|
33
|
+
this.expressionName = config?.expressionName ?? 'publish';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
apply(player: Player) {
|
|
37
|
+
player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
|
|
38
|
+
const existingExpression = expEvaluator.operators.expressions.get(
|
|
39
|
+
this.expressionName
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (existingExpression) {
|
|
43
|
+
player.logger.warn(
|
|
44
|
+
`[PubSubPlugin] expression ${this.expressionName} is already registered.`
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
expEvaluator.addExpressionFunction(
|
|
48
|
+
this.expressionName,
|
|
49
|
+
(_ctx: ExpressionContext, event: unknown, ...args: unknown[]) => {
|
|
50
|
+
if (typeof event === 'string') {
|
|
51
|
+
this.publish(event, ...args);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
player.hooks.onEnd.tap(this.name, () => {
|
|
59
|
+
this.clear();
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A way of publishing an event, notifying any listeners
|
|
65
|
+
*
|
|
66
|
+
* @param event - The name of the event to publish. Can take sub-topics like: foo.bar
|
|
67
|
+
* @param data - Any additional data to attach to the event
|
|
68
|
+
*/
|
|
69
|
+
publish(event: string, ...args: unknown[]) {
|
|
70
|
+
pubsub.publish(event, ...args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe to an event with the given name. The handler will get called for any published event
|
|
75
|
+
*
|
|
76
|
+
* @param event - The name of the event to subscribe to
|
|
77
|
+
* @param handler - A function to be called when the event is triggered
|
|
78
|
+
* @returns A token to be used to unsubscribe from the event
|
|
79
|
+
*/
|
|
80
|
+
subscribe<T extends string, A extends unknown[]>(
|
|
81
|
+
event: T,
|
|
82
|
+
handler: SubscribeHandler<T, A>
|
|
83
|
+
) {
|
|
84
|
+
return pubsub.subscribe(event, handler);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Remove any subscriptions using the given token
|
|
89
|
+
*
|
|
90
|
+
* @param token - A token from a `subscribe` call
|
|
91
|
+
*/
|
|
92
|
+
unsubscribe(token: string) {
|
|
93
|
+
pubsub.unsubscribe(token);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Remove all subscriptions
|
|
98
|
+
*/
|
|
99
|
+
clear() {
|
|
100
|
+
pubsub.clear();
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/pubsub.ts
CHANGED
|
@@ -1,77 +1,173 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Based off the pubsub-js library and rewritten to match the same used APIs but modified so that
|
|
3
|
+
* multiple arguments could be passed into the publish and subscription handlers.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type SubscribeHandler<T extends string, A extends unknown[]> = (
|
|
7
|
+
type: T,
|
|
8
|
+
...args: A
|
|
9
|
+
) => void;
|
|
10
|
+
|
|
11
|
+
export type PubSubUUID = `uuid_${number}`;
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
|
-
*
|
|
16
|
-
* It injects a publish() function into the expression language, and will forward all events back to any subscribers.
|
|
17
|
-
*
|
|
18
|
-
* Published/Subscribed events support a hierarchy:
|
|
19
|
-
* - publish('foo', 'data') -- will trigger any listeners for 'foo'
|
|
20
|
-
* - publish('foo.bar', 'data') -- will trigger any listeners for 'foo' or 'foo.bar'
|
|
21
|
-
*
|
|
14
|
+
* Split a string into an array of event layers
|
|
22
15
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
function splitEvent(event: string) {
|
|
17
|
+
return event.split('.').reduce<string[]>((prev, curr, index) => {
|
|
18
|
+
if (index === 0) {
|
|
19
|
+
return [curr];
|
|
20
|
+
}
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
return [...prev, `${prev[index - 1]}.${curr}`];
|
|
23
|
+
}, []);
|
|
24
|
+
}
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
let count = 1;
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Tiny pubsub maker
|
|
30
|
+
*/
|
|
31
|
+
class TinyPubSub {
|
|
32
|
+
private events: Map<string, Map<PubSubUUID, SubscribeHandler<any, any>>>;
|
|
33
|
+
private tokens: Map<PubSubUUID, string>;
|
|
34
|
+
|
|
35
|
+
constructor() {
|
|
36
|
+
this.events = new Map();
|
|
37
|
+
this.tokens = new Map();
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
);
|
|
45
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Publish an event with any number of additional arguments
|
|
42
|
+
*/
|
|
43
|
+
publish(event: string, ...args: unknown[]) {
|
|
44
|
+
if (typeof event !== 'string') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (event.includes('.')) {
|
|
49
|
+
const eventKeys = splitEvent(event);
|
|
50
|
+
|
|
51
|
+
eventKeys.forEach((key) => {
|
|
52
|
+
this.deliver(key, event, ...args);
|
|
53
|
+
});
|
|
54
|
+
} else {
|
|
55
|
+
this.deliver(event, event, ...args);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.deliver('*', event, ...args);
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
/**
|
|
49
|
-
*
|
|
62
|
+
* Subscribe to an event
|
|
63
|
+
*
|
|
64
|
+
* Events are also heirarchical when separated by a period. Given the following:
|
|
50
65
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
66
|
+
* publish('a.b.c', 'one', 'two', 'three)
|
|
67
|
+
*
|
|
68
|
+
* The subscribe event will be called when the event is passed as 'a', 'a.b', or 'a.b.c'.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // subscribes to the top level 'a' publish
|
|
72
|
+
* subscribe('a', (event, ...args) => console.log(event, ...args))
|
|
53
73
|
*/
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
subscribe(event: string, handler: SubscribeHandler<any, any>) {
|
|
75
|
+
const uuid = `uuid_${++count}`;
|
|
76
|
+
|
|
77
|
+
if (typeof event === 'string') {
|
|
78
|
+
if (!this.events.has(event)) {
|
|
79
|
+
this.events.set(event, new Map());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const handlers = this.events.get(event);
|
|
83
|
+
handlers!.set(uuid as PubSubUUID, handler);
|
|
84
|
+
this.tokens.set(uuid as PubSubUUID, event);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return uuid;
|
|
56
88
|
}
|
|
57
89
|
|
|
58
90
|
/**
|
|
59
|
-
*
|
|
91
|
+
* Unsubscribes to a specific subscription given it's symbol or an entire
|
|
92
|
+
* event when passed as a string.
|
|
60
93
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
94
|
+
* When existing subscriptions exist for heirarchical events such as 'a.b.c',
|
|
95
|
+
* when passing an event 'a' to unsubscribe, all subscriptions for 'a', 'a.b',
|
|
96
|
+
* & 'a.b.c' will be unsubscribed as well.
|
|
64
97
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
98
|
+
unsubscribe(value: string | symbol) {
|
|
99
|
+
if (typeof value === 'string' && value.startsWith('uuid')) {
|
|
100
|
+
const path = this.tokens.get(value as PubSubUUID);
|
|
101
|
+
|
|
102
|
+
if (typeof path === 'undefined') {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const innerPath = this.events.get(path);
|
|
107
|
+
innerPath?.delete(value as PubSubUUID);
|
|
108
|
+
this.tokens.delete(value as PubSubUUID);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (typeof value === 'string') {
|
|
113
|
+
for (const key of this.events.keys()) {
|
|
114
|
+
if (key.indexOf(value) === 0) {
|
|
115
|
+
const tokens = this.events.get(key);
|
|
116
|
+
|
|
117
|
+
if (tokens && tokens.size) {
|
|
118
|
+
// eslint-disable-next-line max-depth
|
|
119
|
+
for (const token of tokens.keys()) {
|
|
120
|
+
this.tokens.delete(token);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.events.delete(key);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
67
128
|
}
|
|
68
129
|
|
|
69
130
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* @param token - A token from a `subscribe` call
|
|
131
|
+
* Get the number of subscriptions for a specific event, or when left blank
|
|
132
|
+
* will return the overall number of subscriptions for the entire pubsub.
|
|
73
133
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
134
|
+
count(event?: string) {
|
|
135
|
+
let counter = 0;
|
|
136
|
+
|
|
137
|
+
if (typeof event === 'undefined') {
|
|
138
|
+
for (const handlers of this.events.values()) {
|
|
139
|
+
counter += handlers.size;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return counter;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const handlers = this.events.get(event);
|
|
146
|
+
|
|
147
|
+
if (handlers?.size) {
|
|
148
|
+
return handlers.size;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return counter;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Deletes all existing subscriptions
|
|
156
|
+
*/
|
|
157
|
+
clear() {
|
|
158
|
+
this.events.clear();
|
|
159
|
+
this.tokens.clear();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private deliver(path: string, event: string, ...args: unknown[]) {
|
|
163
|
+
const handlers = this.events.get(path);
|
|
164
|
+
|
|
165
|
+
if (handlers && handlers.size) {
|
|
166
|
+
for (const handler of handlers.values()) {
|
|
167
|
+
handler(event, ...args);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
76
170
|
}
|
|
77
171
|
}
|
|
172
|
+
|
|
173
|
+
export const pubsub = new TinyPubSub();
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Player } from '@player-ui/player';
|
|
2
|
+
import { PubSubPlugin } from './plugin';
|
|
3
|
+
import { PubSubPluginSymbol } from './symbols';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns the existing PubSubPlugin or creates and registers a new plugin
|
|
7
|
+
*/
|
|
8
|
+
export function getPubSubPlugin(player: Player) {
|
|
9
|
+
const existing = player.findPlugin<PubSubPlugin>(PubSubPluginSymbol);
|
|
10
|
+
const plugin = existing || new PubSubPlugin();
|
|
11
|
+
|
|
12
|
+
if (!existing) {
|
|
13
|
+
player.registerPlugin(plugin);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return plugin;
|
|
17
|
+
}
|