lightning-base-components 1.13.9-alpha → 1.14.1-alpha
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/package.json +5 -1
- package/scopedImports/@salesforce-internal-core.appVersion.js +1 -1
- package/scopedImports/@salesforce-label-LightningLookup.recentItems.js +1 -0
- package/src/lightning/baseCombobox/baseCombobox.html +1 -0
- package/src/lightning/baseCombobox/baseCombobox.js +14 -1
- package/src/lightning/combobox/combobox.css +12 -0
- package/src/lightning/combobox/combobox.html +1 -0
- package/src/lightning/datatable/columnWidthManager.js +7 -3
- package/src/lightning/datatable/datatable.js +27 -18
- package/src/lightning/datatable/inlineEdit.js +15 -3
- package/src/lightning/datatable/keyboard.js +1077 -933
- package/src/lightning/datatable/resizer.js +91 -108
- package/src/lightning/datatable/state.js +0 -9
- package/src/lightning/datatable/templates/div/div.css +19 -0
- package/src/lightning/datatable/templates/div/div.html +5 -5
- package/src/lightning/datatable/templates/table/table.html +4 -4
- package/src/lightning/datatable/widthManagerShared.js +1 -1
- package/src/lightning/iconSvgTemplates/buildTemplates/templates.js +2 -1
- package/src/lightning/iconSvgTemplates/buildTemplates/utility/contract_alt.html +1 -2
- package/src/lightning/iconSvgTemplates/buildTemplates/utility/contract_doc.html +8 -0
- package/src/lightning/iconSvgTemplatesRtl/buildTemplates/templates.js +2 -1
- package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/contract_alt.html +1 -2
- package/src/lightning/iconSvgTemplatesRtl/buildTemplates/utility/contract_doc.html +8 -0
- package/src/lightning/iconSvgTemplatesUtility/buildTemplates/templates.js +2 -1
- package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/contract_alt.html +1 -2
- package/src/lightning/iconSvgTemplatesUtility/buildTemplates/utility/contract_doc.html +8 -0
- package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/templates.js +2 -1
- package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/contract_alt.html +1 -2
- package/src/lightning/iconSvgTemplatesUtilityRtl/buildTemplates/utility/contract_doc.html +8 -0
- package/src/lightning/input/input.html +0 -1
- package/src/lightning/input/input.js +21 -25
- package/src/lightning/primitiveDatatableIeditPanel/primitiveDatatableIeditPanel.js +20 -0
- package/src/lightning/primitiveDatatableIeditTypeFactory/primitiveDatatableIeditTypeFactory.js +10 -0
- package/src/lightning/primitiveHeaderFactory/nonsortableHeader.html +5 -4
- package/src/lightning/primitiveHeaderFactory/primitiveHeaderFactory.js +46 -46
- package/src/lightning/primitiveHeaderFactory/selectableHeader.html +25 -23
- package/src/lightning/primitiveHeaderFactory/sortableHeader.html +13 -9
- package/src/lightning/progressIndicator/progressIndicator.js +3 -5
- package/src/lightning/progressStep/progressStep.js +2 -1
- package/src/lightning/utilsPrivate/utilsPrivate.js +11 -1
- package/src/lightning/utilsPrivate/contentMutation.js +0 -295
|
@@ -181,44 +181,51 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
|
-
*
|
|
184
|
+
* Computes an option name
|
|
185
185
|
*
|
|
186
|
-
* @return {
|
|
186
|
+
* @return {string} The computed option name
|
|
187
187
|
*/
|
|
188
|
-
get
|
|
189
|
-
return this.
|
|
188
|
+
get computedOptionName() {
|
|
189
|
+
return `${this.dtContextId}-options`;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
|
-
* Determines if
|
|
193
|
+
* Determines if the header has actions available
|
|
194
194
|
*
|
|
195
|
-
* @return {boolean} Whether the
|
|
195
|
+
* @return {boolean} Whether the header has available actions
|
|
196
196
|
*/
|
|
197
|
-
get
|
|
198
|
-
return
|
|
197
|
+
get hasActions() {
|
|
198
|
+
return (
|
|
199
|
+
this.actions.customerActions.length > 0 ||
|
|
200
|
+
this.actions.internalActions.length > 0
|
|
201
|
+
);
|
|
199
202
|
}
|
|
200
203
|
|
|
201
204
|
/**
|
|
202
|
-
* Returns the
|
|
205
|
+
* Returns the header's aria role
|
|
203
206
|
*
|
|
204
|
-
* @return {string}
|
|
207
|
+
* @return {string|boolean} The aria role for the header
|
|
205
208
|
*/
|
|
206
|
-
get
|
|
207
|
-
|
|
208
|
-
return this.sortedDirection === 'desc'
|
|
209
|
-
? i18n.sortDesc
|
|
210
|
-
: i18n.sortAsc;
|
|
211
|
-
}
|
|
212
|
-
return i18n.sortNone;
|
|
209
|
+
get headerRole() {
|
|
210
|
+
return this.isResizable || this.sortable ? 'button' : false;
|
|
213
211
|
}
|
|
214
212
|
|
|
215
213
|
/**
|
|
216
|
-
* Determines if
|
|
214
|
+
* Determines if sort direction is set to ascending
|
|
217
215
|
*
|
|
218
|
-
* @return {boolean} Whether the
|
|
216
|
+
* @return {boolean} Whether the sort direction is ascending
|
|
219
217
|
*/
|
|
220
|
-
get
|
|
221
|
-
return this.
|
|
218
|
+
get isAscSorted() {
|
|
219
|
+
return this.sortedDirection === 'asc';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Determines if sort direction is set to descending
|
|
224
|
+
*
|
|
225
|
+
* @return {boolean} Whether the sort direction is descending
|
|
226
|
+
*/
|
|
227
|
+
get isDescSorted() {
|
|
228
|
+
return this.sortedDirection === 'desc';
|
|
222
229
|
}
|
|
223
230
|
|
|
224
231
|
/**
|
|
@@ -239,6 +246,15 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
239
246
|
return this.resizable && this.def.resizable !== false;
|
|
240
247
|
}
|
|
241
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Determines if the header is selectable
|
|
251
|
+
*
|
|
252
|
+
* @return {boolean} Whether the header is selectable
|
|
253
|
+
*/
|
|
254
|
+
get isSelectableHeader() {
|
|
255
|
+
return this.def.type === 'SELECTABLE_CHECKBOX';
|
|
256
|
+
}
|
|
257
|
+
|
|
242
258
|
/**
|
|
243
259
|
* Determines if the header is sortable
|
|
244
260
|
*
|
|
@@ -257,15 +273,6 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
257
273
|
return i18n;
|
|
258
274
|
}
|
|
259
275
|
|
|
260
|
-
/**
|
|
261
|
-
* Returns the header's aria role
|
|
262
|
-
*
|
|
263
|
-
* @return {string|boolean} The aria role for the header
|
|
264
|
-
*/
|
|
265
|
-
get headerRole() {
|
|
266
|
-
return this.isResizable || this.sortable ? 'button' : false;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
276
|
/**
|
|
270
277
|
* Returns the header's resize step
|
|
271
278
|
*
|
|
@@ -276,24 +283,17 @@ export default class PrimitiveHeaderFactory extends PrimitiveDatatableCell {
|
|
|
276
283
|
}
|
|
277
284
|
|
|
278
285
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* @return {string} The computed option name
|
|
282
|
-
*/
|
|
283
|
-
get computedOptionName() {
|
|
284
|
-
return `${this.dtContextId}-options`;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Determines if the header has actions available
|
|
286
|
+
* Returns the sort order label in the appropriate language
|
|
289
287
|
*
|
|
290
|
-
* @return {
|
|
288
|
+
* @return {string} Language-specific sort order label
|
|
291
289
|
*/
|
|
292
|
-
get
|
|
293
|
-
|
|
294
|
-
this.
|
|
295
|
-
|
|
296
|
-
|
|
290
|
+
get sortedOrderLabel() {
|
|
291
|
+
if (this.sorted) {
|
|
292
|
+
return this.sortedDirection === 'desc'
|
|
293
|
+
? i18n.sortDesc
|
|
294
|
+
: i18n.sortAsc;
|
|
295
|
+
}
|
|
296
|
+
return i18n.sortNone;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
/************************** LIFECYCLE HOOKS **************************/
|
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
<!-- Header Content -->
|
|
3
|
+
<div class="slds-th__action slds-th__action_form slds-cell-fixed" style={columnStyles}>
|
|
4
4
|
<template if:true={showCheckbox}>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
5
|
+
<span class="slds-checkbox">
|
|
6
|
+
|
|
7
|
+
<!-- Selectable Checkbox -->
|
|
8
|
+
<input
|
|
9
|
+
type="checkbox"
|
|
10
|
+
class="datatable-select-all"
|
|
11
|
+
name={computedOptionName}
|
|
12
|
+
id="lgt-dt-header-factory-id"
|
|
13
|
+
onclick={handleSelectAllRows}
|
|
14
|
+
tabindex={internalTabIndex}
|
|
15
|
+
data-navigation="enable"
|
|
16
|
+
disabled={def.isBulkSelectionDisabled}>
|
|
17
|
+
|
|
18
|
+
<label class="slds-checkbox__label" for="lgt-dt-header-factory-id">
|
|
19
|
+
<span class="slds-checkbox_faux"></span>
|
|
20
|
+
<span class="slds-form-element__label slds-assistive-text">
|
|
21
|
+
{i18n.selectAll}
|
|
22
|
+
</span>
|
|
23
|
+
</label>
|
|
24
|
+
</span>
|
|
23
25
|
</template>
|
|
24
26
|
<template if:false={showCheckbox}>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
<span id="column-group-header" class="slds-assistive-text" data-column-header>
|
|
28
|
+
{i18n.chooseARow}
|
|
29
|
+
</span>
|
|
28
30
|
</template>
|
|
29
31
|
</div>
|
|
30
32
|
</template>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
style={columnStyles}
|
|
6
|
-
>
|
|
2
|
+
<!-- Header Content -->
|
|
3
|
+
<span class={computedClass} tabindex={internalTabIndex} style={columnStyles}>
|
|
4
|
+
|
|
7
5
|
<a href="javascript:void(0);"
|
|
8
6
|
class={computedSortClass}
|
|
9
7
|
role={headerRole}
|
|
10
8
|
tabindex={internalTabIndex}
|
|
11
9
|
data-navigation="enable"
|
|
12
10
|
onclick={handleSortingClick}
|
|
13
|
-
style={columnStyles}
|
|
11
|
+
style={columnStyles}
|
|
12
|
+
data-action-triggers="enter">
|
|
14
13
|
|
|
15
14
|
<span class="slds-assistive-text">{i18n.sort}</span>
|
|
16
15
|
|
|
16
|
+
<!-- Icon to display to the left/start of the header text -->
|
|
17
17
|
<template if:true={def.iconName}>
|
|
18
18
|
<div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
|
|
19
19
|
<lightning-icon icon-name={def.iconName} size="x-small" class="slds-icon_container slds-m-right_xx-small" alternative-text={def.label} title={def.label}></lightning-icon>
|
|
@@ -21,17 +21,18 @@
|
|
|
21
21
|
<span class="slds-truncate">{def.label}</span>
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
|
+
<!-- Arrow Icon - Rotates based on sorting direction -->
|
|
24
25
|
<lightning-primitive-icon
|
|
25
26
|
class="slds-icon_container"
|
|
26
27
|
svg-class="slds-icon slds-icon-text-default slds-is-sortable__icon"
|
|
27
28
|
icon-name="utility:arrowdown"
|
|
28
29
|
size="x-small">
|
|
29
30
|
</lightning-primitive-icon>
|
|
30
|
-
|
|
31
31
|
</div>
|
|
32
32
|
</template>
|
|
33
33
|
<template if:false={def.iconName}>
|
|
34
34
|
<span class="slds-truncate" title={def.label}>{def.label}</span>
|
|
35
|
+
<!-- Arrow Icon - Rotates based on sorting direction -->
|
|
35
36
|
<lightning-primitive-icon
|
|
36
37
|
class="slds-icon_container"
|
|
37
38
|
svg-class="slds-icon slds-icon-text-default slds-is-sortable__icon"
|
|
@@ -41,17 +42,20 @@
|
|
|
41
42
|
</template>
|
|
42
43
|
</a>
|
|
43
44
|
|
|
45
|
+
<!-- Aria Live Region to announce sorting order -->
|
|
44
46
|
<span class="slds-assistive-text" aria-live="polite" aria-atomic="true">{sortedOrderLabel}</span>
|
|
45
47
|
|
|
48
|
+
<!-- Header Actions -->
|
|
46
49
|
<template if:true={hasActions}>
|
|
47
50
|
<lightning-primitive-header-actions
|
|
48
51
|
col-key-value={def.colKeyValue}
|
|
49
52
|
actions={actions}
|
|
50
53
|
tabindex={internalTabIndex}
|
|
51
|
-
data-navigation="enable"
|
|
52
|
-
|
|
54
|
+
data-navigation="enable">
|
|
55
|
+
</lightning-primitive-header-actions>
|
|
53
56
|
</template>
|
|
54
57
|
|
|
58
|
+
<!-- Resize Handler -->
|
|
55
59
|
<template if:true={isResizable}>
|
|
56
60
|
<lightning-primitive-resize-handler
|
|
57
61
|
value={columnWidth}
|
|
@@ -100,18 +100,16 @@ export default class LightningProgressIndicator extends LightningElement {
|
|
|
100
100
|
const currentStepIndex = getCurrentStepIndex(steps, currentStep);
|
|
101
101
|
|
|
102
102
|
let activeStepIndex = -1;
|
|
103
|
-
|
|
104
|
-
// Set activeStep index to activeStep if provided.
|
|
103
|
+
// Set activeStepIndex to activeStep if provided.
|
|
105
104
|
// This happens when focus is updated by user using arrow keys or clicking a progress step.
|
|
106
105
|
// When component re-renders, active step is not passed from renderedCallback or handleSlotChange
|
|
107
106
|
// In this scenario, use the privateActiveStepIndex to maintain the activeStep.
|
|
108
107
|
// privateActiveStepInde will have the active step before the re-render
|
|
109
|
-
// In case of initial render, privateActiveStepIndex is
|
|
108
|
+
// In case of initial render, privateActiveStepIndex is undefined. Use privateCurrentStep as activeStepIndex for fallback.
|
|
110
109
|
// activeStep is needed to set active class and proper tabIndex for the progress step
|
|
111
|
-
|
|
112
110
|
if (activeStep) {
|
|
113
111
|
activeStepIndex = getStepIndex(steps, activeStep);
|
|
114
|
-
} else if (this.privateActiveStepIndex) {
|
|
112
|
+
} else if (this.privateActiveStepIndex !== undefined) {
|
|
115
113
|
activeStepIndex = this.privateActiveStepIndex;
|
|
116
114
|
} else {
|
|
117
115
|
activeStepIndex = getStepIndex(steps, this.privateCurrentStep);
|
|
@@ -87,7 +87,8 @@ export default class LightningProgressStep extends LightningElement {
|
|
|
87
87
|
'slds-is-completed': !isPath && status === 'completed',
|
|
88
88
|
'slds-has-error': !isPath && status === 'error',
|
|
89
89
|
'slds-is-active':
|
|
90
|
-
|
|
90
|
+
(type !== 'base' && isActive === true) ||
|
|
91
|
+
(type === 'base' && status === 'current'),
|
|
91
92
|
'slds-path__item': isPath,
|
|
92
93
|
'slds-is-complete': isPath && status === 'completed',
|
|
93
94
|
'slds-is-current':
|
|
@@ -23,7 +23,6 @@ export {
|
|
|
23
23
|
} from './keyboard';
|
|
24
24
|
export { raf } from './scroll';
|
|
25
25
|
export { isChrome, isIE11, isSafari } from './browser';
|
|
26
|
-
export { ContentMutation } from './contentMutation';
|
|
27
26
|
export { observePosition } from './observers';
|
|
28
27
|
export { hasOnlyAllowedVideoIframes } from './videoUtils';
|
|
29
28
|
export {
|
|
@@ -212,3 +211,14 @@ export function buttonGroupOrderClass(groupOrder) {
|
|
|
212
211
|
[BUTTON_GROUP_ORDER.ONLY]: 'single-button',
|
|
213
212
|
}[groupOrder];
|
|
214
213
|
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Checks if the given component is native
|
|
217
|
+
* @param {Object} cmp Component instance
|
|
218
|
+
* @returns {Boolean} Whether the component is native
|
|
219
|
+
*/
|
|
220
|
+
export function isNativeComponent(cmp) {
|
|
221
|
+
return !String(cmp?.template?.constructor).includes(
|
|
222
|
+
'function SyntheticShadowRoot'
|
|
223
|
+
);
|
|
224
|
+
}
|
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import { guid } from './guid';
|
|
2
|
-
import { smartSetAttribute } from './smartSetAttribute';
|
|
3
|
-
|
|
4
|
-
const CONTENT_SEPARATOR = '\n';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
<template>
|
|
8
|
-
<span lwc:dom="manual" class="visually-hidden"></span>
|
|
9
|
-
<input>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
class Foo extends LightningElement {
|
|
13
|
-
constructor() {
|
|
14
|
-
super();
|
|
15
|
-
this.ariaObserver = new ContentMutation(this);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
connectedCallback() {
|
|
19
|
-
if (!this.ariaObserver) {
|
|
20
|
-
this.ariaObserver = new ContentMutation(this);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
disconnectedCallback() {
|
|
25
|
-
if (this.ariaObserver) {
|
|
26
|
-
this.ariaObserver.disconnect();
|
|
27
|
-
this.ariaObserver = undefined;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@track ariaLabeledbyValue = '';
|
|
32
|
-
|
|
33
|
-
@api
|
|
34
|
-
get ariaLabeledby() {
|
|
35
|
-
return this.ariaLabeledbyValue; // whatever they set, is what they get back.
|
|
36
|
-
}
|
|
37
|
-
set ariaLabeledby(refs) {
|
|
38
|
-
this.ariaLabeledbyValue = refs;
|
|
39
|
-
this.ariaObserver.link('input', 'aria-labeledby', refs, 'span.visually-hidden');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
renderedCallback() {
|
|
43
|
-
this.ariaObserver.sync();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
**/
|
|
47
|
-
|
|
48
|
-
function getAttr(elm, attr) {
|
|
49
|
-
if (elm.tagName.match(/lightning/i)) {
|
|
50
|
-
return elm[attr];
|
|
51
|
-
}
|
|
52
|
-
return elm.getAttribute(attr);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function extractElements(root, selector) {
|
|
56
|
-
if (typeof selector !== 'string' || selector === '') {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
return [].slice.call(root.querySelectorAll(selector));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function extractContent(elements) {
|
|
63
|
-
return elements
|
|
64
|
-
.map((element) => element.textContent)
|
|
65
|
-
.filter((text) => text.length)
|
|
66
|
-
.join(CONTENT_SEPARATOR);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function splitIds(ids) {
|
|
70
|
-
return (ids + '').trim().split(/\s+/);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function hashIds(ids) {
|
|
74
|
-
return (ids + '')
|
|
75
|
-
.trim()
|
|
76
|
-
.split(/\s+/)
|
|
77
|
-
.reduce((r, v) => {
|
|
78
|
-
r[v] = 1;
|
|
79
|
-
return r;
|
|
80
|
-
}, {});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// this method should check each individual id from computedIds
|
|
84
|
-
// against the existing value of the attrName on elm, and dupe
|
|
85
|
-
// them, and add the new ones.
|
|
86
|
-
function addAriaRefWhenNeeded(elm, attrName, computedIds) {
|
|
87
|
-
const newIds = splitIds(computedIds);
|
|
88
|
-
const oldIds = getAttr(elm, attrName) || '';
|
|
89
|
-
const oldIdsHash = hashIds(oldIds);
|
|
90
|
-
const suffix = [];
|
|
91
|
-
for (let i = 0; i < newIds.length; i += 1) {
|
|
92
|
-
if (!oldIdsHash[newIds[i]]) {
|
|
93
|
-
suffix.push(newIds[i]);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (suffix.length !== 0) {
|
|
98
|
-
smartSetAttribute(
|
|
99
|
-
elm,
|
|
100
|
-
attrName,
|
|
101
|
-
oldIds + (oldIds.length === 0 ? '' : ' ') + suffix.join(' ')
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// this method should check each individual id from computedIds
|
|
107
|
-
// against the existing value of the attrName on elm, and remove
|
|
108
|
-
// them when possible in preparation for some new values.
|
|
109
|
-
function removeAriaRefWhenPossible(elm, attrName, computedIds) {
|
|
110
|
-
const newIds = splitIds(computedIds);
|
|
111
|
-
const oldIds = getAttr(elm, attrName) || '';
|
|
112
|
-
const oldIdsHash = hashIds(oldIds);
|
|
113
|
-
const newValues = [];
|
|
114
|
-
for (let i = 0; i < newIds.length; i += 1) {
|
|
115
|
-
if (!oldIdsHash[newIds[i]]) {
|
|
116
|
-
newValues.push(newIds[i]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
smartSetAttribute(elm, attrName, newValues.join(' '));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export class ContentMutation {
|
|
123
|
-
constructor(component) {
|
|
124
|
-
this.component = component;
|
|
125
|
-
this.template = component.template;
|
|
126
|
-
this.isNative = this.template.constructor
|
|
127
|
-
.toString()
|
|
128
|
-
.match(/\[native code\]/);
|
|
129
|
-
this.state = {};
|
|
130
|
-
this.liveIds = {};
|
|
131
|
-
this.guid = guid();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
connectLiveIdRef(refs, callback) {
|
|
135
|
-
const selector = (refs + '')
|
|
136
|
-
.trim()
|
|
137
|
-
.split(/\s+/)
|
|
138
|
-
.map((ref) => `[id*="${ref}"]`)
|
|
139
|
-
.join(',');
|
|
140
|
-
const liveId = { selector, callback };
|
|
141
|
-
this.liveIds[refs] = liveId;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
link(innerSelector, attrName, ids, placeholderContainerSelector) {
|
|
145
|
-
let attrState = this.state[attrName];
|
|
146
|
-
if (attrState) {
|
|
147
|
-
// note: we don't support linking to a different innerSelector,
|
|
148
|
-
// attrName, or placeholderContainerSelector
|
|
149
|
-
if (!this.isNative) {
|
|
150
|
-
const elm = this.template.querySelector(innerSelector);
|
|
151
|
-
if (elm) {
|
|
152
|
-
// removing the old ids if possible before setting the new ones
|
|
153
|
-
removeAriaRefWhenPossible(elm, attrName, attrState.ids);
|
|
154
|
-
}
|
|
155
|
-
attrState.ids = ids;
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
attrState = this.state[attrName] = {
|
|
159
|
-
ids,
|
|
160
|
-
innerSelector,
|
|
161
|
-
placeholderContainerSelector,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (this.isNative) {
|
|
165
|
-
attrState.outerSelector = (ids + '')
|
|
166
|
-
.trim()
|
|
167
|
-
.split(/\s+/)
|
|
168
|
-
.map((ref) => `#${ref}`)
|
|
169
|
-
.join(',');
|
|
170
|
-
attrState.placeholder = document.createElement('span');
|
|
171
|
-
attrState.placeholder.id = `auto-link-${attrName}-${this.guid}`;
|
|
172
|
-
}
|
|
173
|
-
if (this.component.isConnected) {
|
|
174
|
-
this.privateUpdate(attrName);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
sync() {
|
|
179
|
-
if (!this.component.isConnected) {
|
|
180
|
-
throw new Error(
|
|
181
|
-
`Invalid sync invocation. It can only be invoked during renderedCallback().`
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
if (this.isNative && !this.mo) {
|
|
185
|
-
this.privateConnect();
|
|
186
|
-
}
|
|
187
|
-
for (const attrName in this.state) {
|
|
188
|
-
if (Object.prototype.hasOwnProperty.call(this.state, attrName)) {
|
|
189
|
-
this.privateUpdate(attrName);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// live idRef feature is a no-op in native
|
|
194
|
-
if (!this.isNative) {
|
|
195
|
-
this.privateUpdateLiveIds();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
privateExtractIds(elements) {
|
|
200
|
-
return elements
|
|
201
|
-
.map((el) => {
|
|
202
|
-
return el.getAttribute('id');
|
|
203
|
-
})
|
|
204
|
-
.join(' ');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
privateUpdateLiveIds() {
|
|
208
|
-
const root = this.template.host.getRootNode();
|
|
209
|
-
|
|
210
|
-
// if not connected do nothing
|
|
211
|
-
if (!root) {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
for (const liveId in this.liveIds) {
|
|
215
|
-
if (Object.prototype.hasOwnProperty.call(this.liveIds, liveId)) {
|
|
216
|
-
const thisId = this.liveIds[liveId];
|
|
217
|
-
if (!thisId.elements) {
|
|
218
|
-
// element refs are cached
|
|
219
|
-
thisId.elements = Array.prototype.slice.call(
|
|
220
|
-
root.querySelectorAll(thisId.selector)
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
const newIds = this.privateExtractIds(thisId.elements);
|
|
224
|
-
// only fire calback if the value changed
|
|
225
|
-
if (newIds !== thisId.ids) {
|
|
226
|
-
thisId.callback(newIds);
|
|
227
|
-
thisId.ids = newIds;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
privateUpdate(attrName) {
|
|
234
|
-
const { innerSelector } = this.state[attrName];
|
|
235
|
-
const elm = this.template.querySelector(innerSelector);
|
|
236
|
-
if (!elm) {
|
|
237
|
-
return; // nothing to update
|
|
238
|
-
}
|
|
239
|
-
let computedIds;
|
|
240
|
-
if (this.isNative) {
|
|
241
|
-
const {
|
|
242
|
-
outerSelector,
|
|
243
|
-
content,
|
|
244
|
-
placeholder,
|
|
245
|
-
placeholderContainerSelector,
|
|
246
|
-
} = this.state[attrName];
|
|
247
|
-
const newContent = extractContent(
|
|
248
|
-
extractElements(this.root, outerSelector)
|
|
249
|
-
);
|
|
250
|
-
if (content !== newContent) {
|
|
251
|
-
this.state[attrName].content = placeholder.textContent =
|
|
252
|
-
newContent;
|
|
253
|
-
}
|
|
254
|
-
if (!placeholder.parentNode) {
|
|
255
|
-
// inserting the placeholder once
|
|
256
|
-
const container = this.template.querySelector(
|
|
257
|
-
placeholderContainerSelector
|
|
258
|
-
);
|
|
259
|
-
if (container) {
|
|
260
|
-
container.appendChild(placeholder);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
computedIds = placeholder.id;
|
|
264
|
-
} else {
|
|
265
|
-
computedIds = this.state[attrName].ids;
|
|
266
|
-
}
|
|
267
|
-
addAriaRefWhenNeeded(elm, attrName, computedIds);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
privateConnect() {
|
|
271
|
-
// caching root ref
|
|
272
|
-
this.root = this.template.host.getRootNode();
|
|
273
|
-
// creating the observer once
|
|
274
|
-
this.mo = new MutationObserver(() => {
|
|
275
|
-
if (!this.component.isConnected) {
|
|
276
|
-
return; // do nothing when the template is not connected
|
|
277
|
-
}
|
|
278
|
-
this.sync();
|
|
279
|
-
});
|
|
280
|
-
this.mo.observe(this.root, {
|
|
281
|
-
characterData: true,
|
|
282
|
-
childList: true,
|
|
283
|
-
subtree: true,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
disconnect() {
|
|
288
|
-
// MutationObservers must be disconnected manually when using @lwc/synthetic-shadow
|
|
289
|
-
// https://lwc.dev/guide/composition#:~:text=memory%20leak
|
|
290
|
-
if (this.mo) {
|
|
291
|
-
this.mo.disconnect();
|
|
292
|
-
this.mo = undefined;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|