-
Notifications
You must be signed in to change notification settings - Fork 25
/
selection-observer-mixin.js
112 lines (94 loc) · 2.95 KB
/
selection-observer-mixin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { cssEscape } from '../../helpers/dom.js';
import { SelectionInfo } from './selection-mixin.js';
export const SelectionObserverMixin = superclass => class extends superclass {
static get properties() {
return {
/**
* Id of the `SelectionMixin` component this component wants to observe (if not located within that component)
* @type {string}
*/
selectionFor: { type: String, reflect: true, attribute: 'selection-for' },
/**
* The selection info (set by the selection component)
* @ignore
* @type {object}
*/
selectionInfo: { type: Object },
_provider: { type: Object, attribute: false }
};
}
constructor() {
super();
this.selectionInfo = new SelectionInfo();
this._provider = null;
}
connectedCallback() {
super.connectedCallback();
this.addEventListener('d2l-selection-observer-subscribe', this._handleSelectionObserverSubscribe);
// delay subscription otherwise import/upgrade order can cause selection mixin to miss event
requestAnimationFrame(() => {
if (this.selectionFor) {
this._handleSelectionFor();
return this._provider?.subscribeObserver(this);
}
const evt = new CustomEvent('d2l-selection-observer-subscribe', {
bubbles: true,
composed: true,
detail: {}
});
this.dispatchEvent(evt);
this._provider = evt.detail.provider;
});
}
disconnectedCallback() {
super.disconnectedCallback();
this._disconnectSelectionForObserver();
this._disconnectProvider();
this.removeEventListener('d2l-selection-observer-subscribe', this._handleSelectionObserverSubscribe);
}
updated(changedProperties) {
super.updated(changedProperties);
if (changedProperties.has('selectionFor')) this._handleSelectionFor();
}
_disconnectProvider() {
if (!this._provider) return;
this._provider.unsubscribeObserver(this);
this._provider = undefined;
}
_disconnectSelectionForObserver() {
if (!this._selectionForObserver) return;
this._selectionForObserver.disconnect();
this._selectionForObserver = undefined;
}
_handleSelectionFor() {
this._disconnectSelectionForObserver();
this._updateProvider();
if (this.selectionFor) {
this._selectionForObserver = new MutationObserver(() => this._updateProvider());
this._selectionForObserver.observe(this.getRootNode(), {
childList: true,
subtree: true
});
}
}
_handleSelectionObserverSubscribe(e) {
if (this._provider) {
const target = e.composedPath()[0];
if (target === this) return;
e.stopPropagation();
e.detail.provider = this._provider;
this._provider.subscribeObserver(target);
}
}
_updateProvider() {
const selectionComponent = this.selectionFor ? this.getRootNode().querySelector(`#${cssEscape(this.selectionFor)}`) : undefined;
if (this._provider === selectionComponent) return;
this._disconnectProvider();
this._provider = selectionComponent;
if (this._provider) {
this._provider.subscribeObserver(this);
} else {
this.selectionInfo = new SelectionInfo();
}
}
};