@brightspace-ui/core 2.98.6 → 2.99.0
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/components/filter/filter-tags.js +4 -4
- package/components/filter/filter.js +5 -9
- package/components/list/list-item-expand-collapse-mixin.js +1 -1
- package/components/list/list.js +4 -9
- package/controllers/subscriber/README.md +28 -42
- package/controllers/subscriber/subscriberControllers.js +74 -53
- package/package.json +1 -1
|
@@ -36,10 +36,10 @@ class FilterTags extends LocalizeCoreElement(LitElement) {
|
|
|
36
36
|
super();
|
|
37
37
|
|
|
38
38
|
this._allActiveFilters = new Map();
|
|
39
|
-
this._filters = new IdSubscriberController(this,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
39
|
+
this._filters = new IdSubscriberController(this, 'active-filters', {
|
|
40
|
+
idPropertyName: 'filterIds',
|
|
41
|
+
onUnsubscribe: this._removeLostFilter.bind(this)
|
|
42
|
+
});
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
render() {
|
|
@@ -136,7 +136,7 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
|
|
|
136
136
|
line-height: unset;
|
|
137
137
|
overflow: hidden;
|
|
138
138
|
}
|
|
139
|
-
|
|
139
|
+
|
|
140
140
|
.d2l-filter-dimension-set-value-text {
|
|
141
141
|
-webkit-box-orient: vertical;
|
|
142
142
|
display: -webkit-box;
|
|
@@ -191,10 +191,10 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
|
|
|
191
191
|
this._totalAppliedCount = 0;
|
|
192
192
|
|
|
193
193
|
this._activeFilters = null;
|
|
194
|
-
this._activeFiltersSubscribers = new SubscriberRegistryController(this,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
);
|
|
194
|
+
this._activeFiltersSubscribers = new SubscriberRegistryController(this, 'active-filters', {
|
|
195
|
+
onSubscribe: this._updateActiveFiltersSubscriber.bind(this),
|
|
196
|
+
updateSubscribers: this._updateActiveFiltersSubscribers.bind(this)
|
|
197
|
+
});
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
static get focusElementSelector() {
|
|
@@ -268,10 +268,6 @@ class Filter extends FocusMixin(LocalizeCoreElement(RtlMixin(LitElement))) {
|
|
|
268
268
|
`;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
getSubscriberController() {
|
|
272
|
-
return this._activeFiltersSubscribers;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
271
|
requestFilterClearAll() {
|
|
276
272
|
this._handleClearAll();
|
|
277
273
|
}
|
|
@@ -76,7 +76,7 @@ export const ListItemExpandCollapseMixin = superclass => class extends superclas
|
|
|
76
76
|
this._siblingHasNestedItems = false;
|
|
77
77
|
this._renderExpandCollapseSlot = false;
|
|
78
78
|
this._showNestedLoadingSpinner = false;
|
|
79
|
-
this._parentChildUpdateSubscription = new EventSubscriberController(this,
|
|
79
|
+
this._parentChildUpdateSubscription = new EventSubscriberController(this, 'list-child-status');
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
connectedCallback() {
|
package/components/list/list.js
CHANGED
|
@@ -69,11 +69,10 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
69
69
|
this._listItemChanges = [];
|
|
70
70
|
this._childHasExpandCollapseToggle = false;
|
|
71
71
|
|
|
72
|
-
this._listChildrenUpdatedSubscribers = new SubscriberRegistryController(
|
|
73
|
-
this,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
);
|
|
72
|
+
this._listChildrenUpdatedSubscribers = new SubscriberRegistryController(this, 'list-child-status', {
|
|
73
|
+
onSubscribe: this._updateActiveSubscriber.bind(this),
|
|
74
|
+
updateSubscribers: this._updateActiveSubscribers.bind(this)
|
|
75
|
+
});
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
connectedCallback() {
|
|
@@ -185,10 +184,6 @@ class List extends PageableMixin(SelectionMixin(LitElement)) {
|
|
|
185
184
|
return new SelectionInfo(keys, selectionInfo.state);
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
getSubscriberController() {
|
|
189
|
-
return this._listChildrenUpdatedSubscribers;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
187
|
_getItemByIndex(index) {
|
|
193
188
|
const items = this.getItems();
|
|
194
189
|
if (index > items.length - 1) return;
|
|
@@ -12,29 +12,19 @@ import { SubscriberRegistryController } from '@brightspace-ui/core/controllers/s
|
|
|
12
12
|
class CableSubscription extends LitElement {
|
|
13
13
|
constructor() {
|
|
14
14
|
super();
|
|
15
|
-
this._sportsSubscribers = new SubscriberRegistryController(this,
|
|
16
|
-
{ onSubscribe: this._unlockSportsChannels.bind(this) },
|
|
17
|
-
{ eventName: 'd2l-channels-subscribe-sports' }
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
this._movieSubscribers = new SubscriberRegistryController(this, {},
|
|
21
|
-
{ onSubscribe: this._unlockMovieChannels.bind(this), updateSubscribers: this._sendMovieGuide.bind(this) },
|
|
22
|
-
{ eventName: 'd2l-channels-subscribe-movies' }
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
// This controller only supports registering by id - no event is needed
|
|
26
|
-
this._kidsChannelSubscribers = new SubscriberRegistryController(this,
|
|
27
|
-
{ onSubscribe: this._unlockKidsChannels.bind(this) }, {});
|
|
28
|
-
}
|
|
29
15
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
this._sportsSubscribers = new SubscriberRegistryController(this, 'channels-sports', {
|
|
17
|
+
onSubscribe: this._unlockSportsChannels.bind(this)
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
this._movieSubscribers = new SubscriberRegistryController(this, 'channels-movies', {
|
|
21
|
+
onSubscribe: this._unlockMovieChannels.bind(this),
|
|
22
|
+
updateSubscribers: this._sendMovieGuide.bind(this)
|
|
37
23
|
}
|
|
24
|
+
|
|
25
|
+
this._kidsChannelSubscribers = new SubscriberRegistryController(this, 'channels-kids', {
|
|
26
|
+
onSubscribe: this._unlockKidsChannels.bind(this)
|
|
27
|
+
});
|
|
38
28
|
}
|
|
39
29
|
|
|
40
30
|
_sendMovieGuide(subscribers) {
|
|
@@ -49,15 +39,13 @@ class CableSubscription extends LitElement {
|
|
|
49
39
|
}
|
|
50
40
|
```
|
|
51
41
|
|
|
52
|
-
When creating the controller, you
|
|
53
|
-
|
|
54
|
-
The `*subscriberController`s will use a `getSubscriberController` method that needs to be exposed on the registry component. If you only have one `SubscriberRegistryController` you can simple return that. If you have multiple, you will return the proper controller depending on the id the subscriber component passed to you.
|
|
42
|
+
When creating the controller, you must provide a unique name for the subscription (e.g. `'channels-sports'`). You may also pass in an optional `updateSubscribers` callback (invoked by calling `.updateSubscribers` on the controller, with built-in debouncing), and lifecycle callbacks to run whenever a subscriber is added (`onSubscribe`) or removed (`onUnsubscribe`).
|
|
55
43
|
|
|
56
44
|
Once this has been set up, components can subscribe to particular registries two different ways:
|
|
57
|
-
1. Using
|
|
58
|
-
2.
|
|
45
|
+
1. Using `EventSubscriberController` with the target subscription name. The component will need to be a child of the registry component for this to work.
|
|
46
|
+
2. Using `IdSubscriberController` with the target subscription name and the `idPropertyName` option, which will point to the registry component's id. The component will need to be in the same DOM scope as the registry component for this to work.
|
|
59
47
|
|
|
60
|
-
Like the `SubscriberRegistryController`, these `*subscriberController`s take optional callbacks
|
|
48
|
+
Like the `SubscriberRegistryController`, these `*subscriberController`s take optional callbacks invoked at different points in the subscription process.
|
|
61
49
|
|
|
62
50
|
```js
|
|
63
51
|
import { EventSubscriberController, IdSubscriberController } from '@brightspace-ui/core/controllers/subscriber/subscriberControllers.js';
|
|
@@ -72,15 +60,12 @@ class GeneralViewer extends LitElement {
|
|
|
72
60
|
constructor() {
|
|
73
61
|
super();
|
|
74
62
|
this._subscribedChannels = new Set();
|
|
75
|
-
|
|
76
|
-
this._sportsSubscription = new EventSubscriberController(this,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this._movieSubscription = new EventSubscriberController(this, {},
|
|
82
|
-
{ eventName: 'd2l-channels-subscribe-movies', controllerId: 'movies' }
|
|
83
|
-
);
|
|
63
|
+
|
|
64
|
+
this._sportsSubscription = new EventSubscriberController(this, 'channels-sports', {
|
|
65
|
+
onError: this._onSportsError.bind(this)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this._movieSubscription = new EventSubscriberController(this, 'channels-movies');
|
|
84
69
|
}
|
|
85
70
|
|
|
86
71
|
addChannels(channels) {
|
|
@@ -106,10 +91,11 @@ class YoungerViewer extends LitElement {
|
|
|
106
91
|
super();
|
|
107
92
|
this._subscribedChannels = new Set();
|
|
108
93
|
|
|
109
|
-
this._kidsSubscription = new IdSubscriberController(this,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
94
|
+
this._kidsSubscription = new IdSubscriberController(this, 'channels-kids', {
|
|
95
|
+
idPropertyName: 'for',
|
|
96
|
+
onSubscribe: this._onSubscribe.bind(this),
|
|
97
|
+
onUnsubscribe: this._onUnsubscribe.bind(this)
|
|
98
|
+
});
|
|
113
99
|
}
|
|
114
100
|
|
|
115
101
|
addChannels(channels) {
|
|
@@ -129,6 +115,7 @@ class YoungerViewer extends LitElement {
|
|
|
129
115
|
```
|
|
130
116
|
|
|
131
117
|
An example of what this could look like altogether:
|
|
118
|
+
|
|
132
119
|
```html
|
|
133
120
|
<cable-subscription id="rogers">
|
|
134
121
|
<general-viewer></general-viewer>
|
|
@@ -136,13 +123,12 @@ An example of what this could look like altogether:
|
|
|
136
123
|
<younger-viewer for="rogers"></younger-viewer>
|
|
137
124
|
```
|
|
138
125
|
|
|
139
|
-
As of the Lit 2 upgrade, the lifecycle methods `hostConnected`, `hostDisconnected`, and `hostUpdated` will be called automatically.
|
|
140
126
|
## Available Callbacks
|
|
141
127
|
|
|
142
128
|
### SubscriberRegistryController
|
|
143
129
|
| Callback Name | Description | Passed to Callback |
|
|
144
130
|
|---|---|---|
|
|
145
|
-
| `onSubscribe` | Runs whenever a new subscriber is added | Subscriber that was just subscribed |
|
|
131
|
+
| `onSubscribe` | Runs whenever a new subscriber is added | Subscriber that was just subscribed |
|
|
146
132
|
| `onUnsubscribe` | Runs whenever a subscriber is removed | Subscriber that was just unsubscribed |
|
|
147
133
|
| `updateSubscribers` | Runs whenever `updateSubscribers` is called on the controller, handles debouncing requests for you | Map of all current subscribers |
|
|
148
134
|
|
|
@@ -1,14 +1,52 @@
|
|
|
1
1
|
import { cssEscape } from '../../helpers/dom.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
class BaseController {
|
|
4
|
+
constructor(host, name, options = {}) {
|
|
5
|
+
if (!host || !name) throw new TypeError('SubscriberController: missing host or subscription name');
|
|
4
6
|
|
|
5
|
-
constructor(host, callbacks, options) {
|
|
6
|
-
this._host = host;
|
|
7
7
|
host.addController(this);
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
8
|
+
this._host = host;
|
|
9
|
+
this._name = name;
|
|
10
|
+
this._options = options;
|
|
11
|
+
this._eventName = `d2l-subscribe-${this._name}`;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class BaseSubscriber extends BaseController {
|
|
16
|
+
_subscribe(target = this._host, targetLabel) {
|
|
17
|
+
const isBroadcast = target === this._host;
|
|
18
|
+
|
|
19
|
+
const options = isBroadcast ? { bubbles: true, composed: true } : {};
|
|
20
|
+
const evt = new CustomEvent(this._eventName, {
|
|
21
|
+
...options,
|
|
22
|
+
detail: { subscriber: this._host }
|
|
23
|
+
});
|
|
24
|
+
target.dispatchEvent(evt);
|
|
25
|
+
|
|
26
|
+
const { registry, registryController } = evt.detail;
|
|
27
|
+
if (!registry) {
|
|
28
|
+
if (this._options.onError) this._options.onError();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (targetLabel) {
|
|
33
|
+
this._registries.set(targetLabel, registry);
|
|
34
|
+
this._registryControllers.set(targetLabel, registryController);
|
|
35
|
+
} else {
|
|
36
|
+
this._registry = registry;
|
|
37
|
+
this._registryController = registryController;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (this._options.onSubscribe) this._options.onSubscribe(registry);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class SubscriberRegistryController extends BaseController {
|
|
45
|
+
|
|
46
|
+
constructor(host, name, options) {
|
|
47
|
+
super(host, name, options);
|
|
11
48
|
|
|
49
|
+
this._subscribers = new Map();
|
|
12
50
|
this._handleSubscribe = this._handleSubscribe.bind(this);
|
|
13
51
|
}
|
|
14
52
|
|
|
@@ -27,24 +65,24 @@ export class SubscriberRegistryController {
|
|
|
27
65
|
subscribe(target) {
|
|
28
66
|
if (this._subscribers.has(target)) return;
|
|
29
67
|
this._subscribers.set(target, target);
|
|
30
|
-
if (this.
|
|
68
|
+
if (this._options.onSubscribe) this._options.onSubscribe(target);
|
|
31
69
|
}
|
|
32
70
|
|
|
33
71
|
unsubscribe(target) {
|
|
34
72
|
this._subscribers.delete(target);
|
|
35
|
-
if (this.
|
|
73
|
+
if (this._options.onUnsubscribe) this._options.onUnsubscribe(target);
|
|
36
74
|
}
|
|
37
75
|
|
|
38
76
|
updateSubscribers() {
|
|
39
77
|
if (!this._subscribers || this._subscribers.size === 0) return;
|
|
40
|
-
if (!this.
|
|
78
|
+
if (!this._options.updateSubscribers) return;
|
|
41
79
|
|
|
42
80
|
// debounce the updates
|
|
43
81
|
if (this._updateSubscribersRequested) return;
|
|
44
82
|
|
|
45
83
|
this._updateSubscribersRequested = true;
|
|
46
84
|
setTimeout(() => {
|
|
47
|
-
this.
|
|
85
|
+
this._options.updateSubscribers(this._subscribers);
|
|
48
86
|
this._updateSubscribersRequested = false;
|
|
49
87
|
}, 0);
|
|
50
88
|
}
|
|
@@ -52,20 +90,19 @@ export class SubscriberRegistryController {
|
|
|
52
90
|
_handleSubscribe(e) {
|
|
53
91
|
e.stopPropagation();
|
|
54
92
|
e.detail.registry = this._host;
|
|
55
|
-
|
|
93
|
+
e.detail.registryController = this;
|
|
94
|
+
const target = e.detail.subscriber;
|
|
56
95
|
this.subscribe(target);
|
|
57
96
|
}
|
|
58
97
|
}
|
|
59
98
|
|
|
60
|
-
export class EventSubscriberController {
|
|
99
|
+
export class EventSubscriberController extends BaseSubscriber {
|
|
100
|
+
|
|
101
|
+
constructor(host, name, options) {
|
|
102
|
+
super(host, name, options);
|
|
61
103
|
|
|
62
|
-
constructor(host, callbacks, options) {
|
|
63
|
-
this._host = host;
|
|
64
|
-
host.addController(this);
|
|
65
|
-
this._callbacks = callbacks || {};
|
|
66
|
-
this._eventName = options && options.eventName;
|
|
67
|
-
this._controllerId = options && options.controllerId;
|
|
68
104
|
this._registry = null;
|
|
105
|
+
this._registryController = null;
|
|
69
106
|
}
|
|
70
107
|
|
|
71
108
|
get registry() {
|
|
@@ -74,39 +111,24 @@ export class EventSubscriberController {
|
|
|
74
111
|
|
|
75
112
|
hostConnected() {
|
|
76
113
|
// delay subscription otherwise import/upgrade order can cause selection mixin to miss event
|
|
77
|
-
requestAnimationFrame(() =>
|
|
78
|
-
const evt = new CustomEvent(this._eventName, {
|
|
79
|
-
bubbles: true,
|
|
80
|
-
composed: true,
|
|
81
|
-
detail: {}
|
|
82
|
-
});
|
|
83
|
-
this._host.dispatchEvent(evt);
|
|
84
|
-
this._registry = evt.detail.registry;
|
|
85
|
-
|
|
86
|
-
if (!this._registry) {
|
|
87
|
-
if (this._callbacks.onError) this._callbacks.onError();
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(this._registry);
|
|
91
|
-
});
|
|
114
|
+
requestAnimationFrame(() => this._subscribe());
|
|
92
115
|
}
|
|
93
116
|
|
|
94
117
|
hostDisconnected() {
|
|
95
|
-
if (this.
|
|
118
|
+
if (this._registryController) this._registryController.unsubscribe(this._host);
|
|
96
119
|
}
|
|
97
120
|
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
export class IdSubscriberController {
|
|
123
|
+
export class IdSubscriberController extends BaseSubscriber {
|
|
124
|
+
|
|
125
|
+
constructor(host, name, options) {
|
|
126
|
+
super(host, name, options);
|
|
101
127
|
|
|
102
|
-
constructor(host, callbacks, options) {
|
|
103
|
-
this._host = host;
|
|
104
|
-
host.addController(this);
|
|
105
|
-
this._callbacks = callbacks || {};
|
|
106
128
|
this._idPropertyName = options && options.idPropertyName;
|
|
107
129
|
this._idPropertyValue = this._idPropertyName ? this._host[this._idPropertyName] : undefined;
|
|
108
|
-
this._controllerId = options && options.controllerId;
|
|
109
130
|
this._registries = new Map();
|
|
131
|
+
this._registryControllers = new Map();
|
|
110
132
|
this._timeouts = new Set();
|
|
111
133
|
}
|
|
112
134
|
|
|
@@ -117,8 +139,8 @@ export class IdSubscriberController {
|
|
|
117
139
|
hostDisconnected() {
|
|
118
140
|
if (this._registryObserver) this._registryObserver.disconnect();
|
|
119
141
|
this._timeouts.forEach(timeoutId => clearTimeout(timeoutId));
|
|
120
|
-
this.
|
|
121
|
-
|
|
142
|
+
this._registryControllers.forEach(controller => {
|
|
143
|
+
controller.unsubscribe(this._host);
|
|
122
144
|
});
|
|
123
145
|
}
|
|
124
146
|
|
|
@@ -129,11 +151,12 @@ export class IdSubscriberController {
|
|
|
129
151
|
this._idPropertyValue = propertyValue;
|
|
130
152
|
|
|
131
153
|
if (this._registryObserver) this._registryObserver.disconnect();
|
|
132
|
-
this.
|
|
133
|
-
|
|
134
|
-
if (this.
|
|
154
|
+
this._registryControllers.forEach((controller, key) => {
|
|
155
|
+
controller.unsubscribe(this._host);
|
|
156
|
+
if (this._options.onUnsubscribe) this._options.onUnsubscribe(key);
|
|
135
157
|
});
|
|
136
158
|
this._registries = new Map();
|
|
159
|
+
this._registryControllers = new Map();
|
|
137
160
|
|
|
138
161
|
this._updateRegistries();
|
|
139
162
|
|
|
@@ -159,7 +182,7 @@ export class IdSubscriberController {
|
|
|
159
182
|
|
|
160
183
|
_updateRegistry(registryId, elapsedTime) {
|
|
161
184
|
let registryComponent = this._host.getRootNode().querySelector(`#${cssEscape(registryId)}`);
|
|
162
|
-
if (!registryComponent && this.
|
|
185
|
+
if (!registryComponent && this._options.onError) {
|
|
163
186
|
if (elapsedTime < 3000) {
|
|
164
187
|
const timeoutId = setTimeout(() => {
|
|
165
188
|
this._timeouts.delete(timeoutId);
|
|
@@ -167,20 +190,18 @@ export class IdSubscriberController {
|
|
|
167
190
|
}, 100);
|
|
168
191
|
this._timeouts.add(timeoutId);
|
|
169
192
|
} else {
|
|
170
|
-
this.
|
|
193
|
+
this._options.onError(registryId);
|
|
171
194
|
}
|
|
172
195
|
}
|
|
173
196
|
|
|
174
197
|
registryComponent = registryComponent || undefined;
|
|
175
198
|
if (this._registries.get(registryId) === registryComponent) return;
|
|
176
199
|
|
|
177
|
-
if (registryComponent)
|
|
178
|
-
|
|
179
|
-
this._registries.set(registryId, registryComponent);
|
|
180
|
-
if (this._callbacks.onSubscribe) this._callbacks.onSubscribe(registryComponent);
|
|
181
|
-
} else {
|
|
200
|
+
if (registryComponent) this._subscribe(registryComponent, registryId);
|
|
201
|
+
else {
|
|
182
202
|
this._registries.delete(registryId);
|
|
183
|
-
|
|
203
|
+
this._registryControllers.delete(registryId);
|
|
204
|
+
if (this._options.onUnsubscribe) this._options.onUnsubscribe(registryId);
|
|
184
205
|
}
|
|
185
206
|
}
|
|
186
207
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brightspace-ui/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.99.0",
|
|
4
4
|
"description": "A collection of accessible, free, open-source web components for building Brightspace applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://github.com/BrightspaceUI/core.git",
|