advanced_select 0.1.6 → 0.1.7
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.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/app/javascript/advanced_select/advanced_select_controller.js +85 -26
- data/lib/advanced_select/helper.rb +13 -3
- data/lib/advanced_select/version.rb +1 -1
- data/lib/generators/advanced_select/install/templates/advanced_select_controller.js +147 -27
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0e19ef001d7d6c5ca336850d173c8b0f18397d8b03de9d77ce0f52506cf7b62
|
|
4
|
+
data.tar.gz: 374e46c6892ca911d29ddeba525ac3f9695a2c2f166028223f0c577b5f56c3fb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30d707af2c9f59b38535c99bebe961f29097fa934451d3e539201f1519951f0ed306fde9afca729c64e8fff2c78ac7cda75f45b72288fc68404df3b335d42fd2
|
|
7
|
+
data.tar.gz: e4099f22327d3b4274bb419c80616684eed98db8d76997fbf33d57ffe96df10ace487b2df0f53fdd87a1033c387c1fbff1e1b6cc056c46a61c74e92bf54a634a
|
data/README.md
CHANGED
|
@@ -77,7 +77,7 @@ AdvancedSelect does not provide query objects, model concerns, authorization log
|
|
|
77
77
|
Add the gem to the host Rails app:
|
|
78
78
|
|
|
79
79
|
```ruby
|
|
80
|
-
gem "advanced_select", "~> 0.1.
|
|
80
|
+
gem "advanced_select", "~> 0.1.7"
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
Run the installer:
|
|
@@ -488,19 +488,20 @@ The partial is rendered on the server for the initial selection, and the control
|
|
|
488
488
|
|
|
489
489
|
- `data-advanced-select-tooltip-list` on the element that holds the rows (the same hook the built-in list uses).
|
|
490
490
|
- `<template data-advanced-select-tooltip-template>` containing the markup for a single selected row.
|
|
491
|
-
- `data-advanced-select-tooltip-field="…"` on the elements inside the template that should be filled in. Available fields
|
|
491
|
+
- `data-advanced-select-tooltip-field="…"` on the elements inside the template that should be filled in. Available fields include `id`, `value`, `label`, `display_label`, extra option keys, and nested paths such as `test.name`; values are written with `textContent` (text only, no markup).
|
|
492
492
|
|
|
493
493
|
```erb
|
|
494
494
|
<%# app/views/alternatives/_tooltip.html.erb %>
|
|
495
495
|
<table>
|
|
496
496
|
<thead>
|
|
497
|
-
<tr><th>Code & Name</th><th>Type</th></tr>
|
|
497
|
+
<tr><th>Code & Name</th><th>Type</th><th>Test</th></tr>
|
|
498
498
|
</thead>
|
|
499
499
|
<tbody data-advanced-select-tooltip-list>
|
|
500
500
|
<% selected_options.each do |option| %>
|
|
501
501
|
<tr>
|
|
502
502
|
<td><%= option.fetch(:display_label) %></td>
|
|
503
503
|
<td><%= option.fetch(:value) %></td>
|
|
504
|
+
<td><%= option.dig(:test, :name) %></td>
|
|
504
505
|
</tr>
|
|
505
506
|
<% end %>
|
|
506
507
|
</tbody>
|
|
@@ -508,6 +509,7 @@ The partial is rendered on the server for the initial selection, and the control
|
|
|
508
509
|
<tr>
|
|
509
510
|
<td data-advanced-select-tooltip-field="display_label"></td>
|
|
510
511
|
<td data-advanced-select-tooltip-field="value"></td>
|
|
512
|
+
<td data-advanced-select-tooltip-field="test.name"></td>
|
|
511
513
|
</tr>
|
|
512
514
|
</template>
|
|
513
515
|
</table>
|
|
@@ -39,11 +39,7 @@ export default class extends Controller {
|
|
|
39
39
|
this.optionActiveClasses = this.classList(this.element.dataset.advancedSelectOptionActiveClass || "ui-advanced-select-option-active")
|
|
40
40
|
this.addOptionActiveClasses = this.classList(this.element.dataset.advancedSelectAddOptionActiveClass || "")
|
|
41
41
|
this.optionSelectedClasses = this.classList(this.element.dataset.advancedSelectOptionSelectedClass || "")
|
|
42
|
-
this.selectedValue = this.selectedValue.map((option) => (
|
|
43
|
-
...option,
|
|
44
|
-
id: option.id.toString(),
|
|
45
|
-
displayLabel: option.displayLabel || option.label
|
|
46
|
-
}))
|
|
42
|
+
this.selectedValue = this.selectedValue.map((option) => this.normalizeSelectedOption(option))
|
|
47
43
|
this.close = this.close.bind(this)
|
|
48
44
|
this.renderOptionsState()
|
|
49
45
|
this.setupEagerDependentFields()
|
|
@@ -109,7 +105,7 @@ export default class extends Controller {
|
|
|
109
105
|
|
|
110
106
|
choose(event) {
|
|
111
107
|
event.preventDefault()
|
|
112
|
-
this.
|
|
108
|
+
this.selectOptionFromElement(event.currentTarget)
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
add(event) {
|
|
@@ -281,17 +277,28 @@ export default class extends Controller {
|
|
|
281
277
|
}
|
|
282
278
|
|
|
283
279
|
selectOption(value, label, submitValue = value, { displayLabel = label, refreshOptions = this.multipleValue } = {}) {
|
|
284
|
-
|
|
285
|
-
|
|
280
|
+
this.selectOptionData(
|
|
281
|
+
this.normalizeSelectedOption({ id: value, value: submitValue, label, displayLabel }),
|
|
282
|
+
{ refreshOptions }
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
selectOptionFromElement(element, { refreshOptions = this.multipleValue } = {}) {
|
|
287
|
+
this.selectOptionData(this.optionData(element), { refreshOptions })
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
selectOptionData(option, { refreshOptions = this.multipleValue } = {}) {
|
|
291
|
+
const selectedOption = this.normalizeSelectedOption(option)
|
|
292
|
+
const value = selectedOption.id
|
|
286
293
|
|
|
287
294
|
if (this.multipleValue) {
|
|
288
295
|
if (this.selectedValue.some((option) => option.id === value)) {
|
|
289
296
|
this.selectedValue = this.selectedValue.filter((option) => option.id !== value)
|
|
290
297
|
} else {
|
|
291
|
-
this.selectedValue = [
|
|
298
|
+
this.selectedValue = [selectedOption, ...this.selectedValue]
|
|
292
299
|
}
|
|
293
300
|
} else {
|
|
294
|
-
this.selectedValue = [
|
|
301
|
+
this.selectedValue = [selectedOption]
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
this.renderSelection()
|
|
@@ -304,6 +311,51 @@ export default class extends Controller {
|
|
|
304
311
|
}
|
|
305
312
|
}
|
|
306
313
|
|
|
314
|
+
optionData(element) {
|
|
315
|
+
const data = this.parseOptionData(element.dataset.advancedSelectOptionParam)
|
|
316
|
+
const value = element.dataset.advancedSelectValueParam
|
|
317
|
+
const submitValue = element.dataset.advancedSelectSubmitValueParam || value
|
|
318
|
+
const label = element.dataset.advancedSelectLabelParam
|
|
319
|
+
const displayLabel = element.dataset.advancedSelectDisplayLabelParam || label
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
...data,
|
|
323
|
+
id: value,
|
|
324
|
+
value: submitValue,
|
|
325
|
+
label,
|
|
326
|
+
displayLabel
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
parseOptionData(json) {
|
|
331
|
+
if (!json) {
|
|
332
|
+
return {}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
const data = JSON.parse(json)
|
|
337
|
+
return data && typeof data === "object" && !Array.isArray(data) ? data : {}
|
|
338
|
+
} catch (_error) {
|
|
339
|
+
return {}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
normalizeSelectedOption(option) {
|
|
344
|
+
const id = option.id.toString()
|
|
345
|
+
const value = (option.value || id).toString()
|
|
346
|
+
const label = (option.label || option.displayLabel || option.display_label || value).toString()
|
|
347
|
+
const displayLabel = (option.displayLabel || option.display_label || label).toString()
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
...option,
|
|
351
|
+
id,
|
|
352
|
+
value,
|
|
353
|
+
label,
|
|
354
|
+
displayLabel,
|
|
355
|
+
display_label: displayLabel
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
307
359
|
renderSelection() {
|
|
308
360
|
this.hiddenFieldsTarget.replaceChildren(...this.hiddenFieldElements)
|
|
309
361
|
this.summaryTarget.replaceChildren(...this.selectionElements)
|
|
@@ -383,13 +435,7 @@ export default class extends Controller {
|
|
|
383
435
|
return
|
|
384
436
|
}
|
|
385
437
|
|
|
386
|
-
|
|
387
|
-
this.selectOption(
|
|
388
|
-
option.dataset.advancedSelectValueParam,
|
|
389
|
-
option.dataset.advancedSelectLabelParam,
|
|
390
|
-
option.dataset.advancedSelectSubmitValueParam || option.dataset.advancedSelectValueParam,
|
|
391
|
-
{ displayLabel: option.dataset.advancedSelectDisplayLabelParam, refreshOptions: false }
|
|
392
|
-
)
|
|
438
|
+
this.selectOptionFromElement(options[0], { refreshOptions: false })
|
|
393
439
|
}
|
|
394
440
|
|
|
395
441
|
chooseActiveOption() {
|
|
@@ -401,12 +447,7 @@ export default class extends Controller {
|
|
|
401
447
|
this.activeOption.dataset.advancedSelectDisplayLabelParam
|
|
402
448
|
)
|
|
403
449
|
} else {
|
|
404
|
-
this.
|
|
405
|
-
this.activeOption.dataset.advancedSelectValueParam,
|
|
406
|
-
this.activeOption.dataset.advancedSelectLabelParam,
|
|
407
|
-
this.activeOption.dataset.advancedSelectSubmitValueParam || this.activeOption.dataset.advancedSelectValueParam,
|
|
408
|
-
{ displayLabel: this.activeOption.dataset.advancedSelectDisplayLabelParam }
|
|
409
|
-
)
|
|
450
|
+
this.selectOptionFromElement(this.activeOption)
|
|
410
451
|
}
|
|
411
452
|
}
|
|
412
453
|
|
|
@@ -602,11 +643,29 @@ export default class extends Controller {
|
|
|
602
643
|
return this.displayLabel(option)
|
|
603
644
|
}
|
|
604
645
|
|
|
605
|
-
const
|
|
606
|
-
const value = option[field] ?? option[camelizedField]
|
|
646
|
+
const value = this.optionFieldValue(option, field)
|
|
607
647
|
return value === undefined || value === null ? "" : value.toString()
|
|
608
648
|
}
|
|
609
649
|
|
|
650
|
+
optionFieldValue(option, field) {
|
|
651
|
+
const directValue = option[field] ?? option[this.camelize(field)]
|
|
652
|
+
if (directValue !== undefined) {
|
|
653
|
+
return directValue
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return field.split(".").reduce((value, segment) => {
|
|
657
|
+
if (value === undefined || value === null) {
|
|
658
|
+
return undefined
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
return value[segment] ?? value[this.camelize(segment)]
|
|
662
|
+
}, option)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
camelize(value) {
|
|
666
|
+
return value.replace(/_([a-z])/g, (_match, character) => character.toUpperCase())
|
|
667
|
+
}
|
|
668
|
+
|
|
610
669
|
textElement(tagName, className, text) {
|
|
611
670
|
const element = document.createElement(tagName)
|
|
612
671
|
element.className = className
|
|
@@ -642,4 +701,4 @@ export default class extends Controller {
|
|
|
642
701
|
get expanded() {
|
|
643
702
|
return this.triggerTarget.getAttribute("aria-expanded") === "true"
|
|
644
703
|
}
|
|
645
|
-
}
|
|
704
|
+
}
|
|
@@ -50,12 +50,12 @@ module AdvancedSelect
|
|
|
50
50
|
|
|
51
51
|
def advanced_select_selected_options(selected)
|
|
52
52
|
advanced_select_array(selected).map do |option|
|
|
53
|
-
|
|
53
|
+
option.to_h.merge(
|
|
54
54
|
id: option.fetch(:id).to_s,
|
|
55
55
|
value: advanced_select_option_value(option),
|
|
56
56
|
label: advanced_select_option_label(option),
|
|
57
57
|
display_label: advanced_select_option_display_label(option)
|
|
58
|
-
|
|
58
|
+
)
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -79,7 +79,8 @@ module AdvancedSelect
|
|
|
79
79
|
advanced_select_value_param: option.fetch(:id),
|
|
80
80
|
advanced_select_submit_value_param: advanced_select_option_value(option),
|
|
81
81
|
advanced_select_label_param: advanced_select_option_label(option),
|
|
82
|
-
advanced_select_display_label_param: advanced_select_option_display_label(option)
|
|
82
|
+
advanced_select_display_label_param: advanced_select_option_display_label(option),
|
|
83
|
+
advanced_select_option_param: advanced_select_option_payload(option)
|
|
83
84
|
}
|
|
84
85
|
) do
|
|
85
86
|
safe_join([
|
|
@@ -170,6 +171,15 @@ module AdvancedSelect
|
|
|
170
171
|
option[:description].to_s
|
|
171
172
|
end
|
|
172
173
|
|
|
174
|
+
def advanced_select_option_payload(option)
|
|
175
|
+
option.to_h.merge(
|
|
176
|
+
id: option.fetch(:id).to_s,
|
|
177
|
+
value: advanced_select_option_value(option),
|
|
178
|
+
label: advanced_select_option_label(option),
|
|
179
|
+
display_label: advanced_select_option_display_label(option)
|
|
180
|
+
).to_json
|
|
181
|
+
end
|
|
182
|
+
|
|
173
183
|
def advanced_select_display_label(label)
|
|
174
184
|
label.to_s.split(" > ").last
|
|
175
185
|
end
|
|
@@ -39,11 +39,7 @@ export default class extends Controller {
|
|
|
39
39
|
this.optionActiveClasses = this.classList(this.element.dataset.advancedSelectOptionActiveClass || "ui-advanced-select-option-active")
|
|
40
40
|
this.addOptionActiveClasses = this.classList(this.element.dataset.advancedSelectAddOptionActiveClass || "")
|
|
41
41
|
this.optionSelectedClasses = this.classList(this.element.dataset.advancedSelectOptionSelectedClass || "")
|
|
42
|
-
this.selectedValue = this.selectedValue.map((option) => (
|
|
43
|
-
...option,
|
|
44
|
-
id: option.id.toString(),
|
|
45
|
-
displayLabel: option.displayLabel || option.label
|
|
46
|
-
}))
|
|
42
|
+
this.selectedValue = this.selectedValue.map((option) => this.normalizeSelectedOption(option))
|
|
47
43
|
this.close = this.close.bind(this)
|
|
48
44
|
this.renderOptionsState()
|
|
49
45
|
this.setupEagerDependentFields()
|
|
@@ -109,7 +105,7 @@ export default class extends Controller {
|
|
|
109
105
|
|
|
110
106
|
choose(event) {
|
|
111
107
|
event.preventDefault()
|
|
112
|
-
this.
|
|
108
|
+
this.selectOptionFromElement(event.currentTarget)
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
add(event) {
|
|
@@ -281,17 +277,28 @@ export default class extends Controller {
|
|
|
281
277
|
}
|
|
282
278
|
|
|
283
279
|
selectOption(value, label, submitValue = value, { displayLabel = label, refreshOptions = this.multipleValue } = {}) {
|
|
284
|
-
|
|
285
|
-
|
|
280
|
+
this.selectOptionData(
|
|
281
|
+
this.normalizeSelectedOption({ id: value, value: submitValue, label, displayLabel }),
|
|
282
|
+
{ refreshOptions }
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
selectOptionFromElement(element, { refreshOptions = this.multipleValue } = {}) {
|
|
287
|
+
this.selectOptionData(this.optionData(element), { refreshOptions })
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
selectOptionData(option, { refreshOptions = this.multipleValue } = {}) {
|
|
291
|
+
const selectedOption = this.normalizeSelectedOption(option)
|
|
292
|
+
const value = selectedOption.id
|
|
286
293
|
|
|
287
294
|
if (this.multipleValue) {
|
|
288
295
|
if (this.selectedValue.some((option) => option.id === value)) {
|
|
289
296
|
this.selectedValue = this.selectedValue.filter((option) => option.id !== value)
|
|
290
297
|
} else {
|
|
291
|
-
this.selectedValue = [
|
|
298
|
+
this.selectedValue = [selectedOption, ...this.selectedValue]
|
|
292
299
|
}
|
|
293
300
|
} else {
|
|
294
|
-
this.selectedValue = [
|
|
301
|
+
this.selectedValue = [selectedOption]
|
|
295
302
|
}
|
|
296
303
|
|
|
297
304
|
this.renderSelection()
|
|
@@ -304,6 +311,51 @@ export default class extends Controller {
|
|
|
304
311
|
}
|
|
305
312
|
}
|
|
306
313
|
|
|
314
|
+
optionData(element) {
|
|
315
|
+
const data = this.parseOptionData(element.dataset.advancedSelectOptionParam)
|
|
316
|
+
const value = element.dataset.advancedSelectValueParam
|
|
317
|
+
const submitValue = element.dataset.advancedSelectSubmitValueParam || value
|
|
318
|
+
const label = element.dataset.advancedSelectLabelParam
|
|
319
|
+
const displayLabel = element.dataset.advancedSelectDisplayLabelParam || label
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
...data,
|
|
323
|
+
id: value,
|
|
324
|
+
value: submitValue,
|
|
325
|
+
label,
|
|
326
|
+
displayLabel
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
parseOptionData(json) {
|
|
331
|
+
if (!json) {
|
|
332
|
+
return {}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
const data = JSON.parse(json)
|
|
337
|
+
return data && typeof data === "object" && !Array.isArray(data) ? data : {}
|
|
338
|
+
} catch (_error) {
|
|
339
|
+
return {}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
normalizeSelectedOption(option) {
|
|
344
|
+
const id = option.id.toString()
|
|
345
|
+
const value = (option.value || id).toString()
|
|
346
|
+
const label = (option.label || option.displayLabel || option.display_label || value).toString()
|
|
347
|
+
const displayLabel = (option.displayLabel || option.display_label || label).toString()
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
...option,
|
|
351
|
+
id,
|
|
352
|
+
value,
|
|
353
|
+
label,
|
|
354
|
+
displayLabel,
|
|
355
|
+
display_label: displayLabel
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
307
359
|
renderSelection() {
|
|
308
360
|
this.hiddenFieldsTarget.replaceChildren(...this.hiddenFieldElements)
|
|
309
361
|
this.summaryTarget.replaceChildren(...this.selectionElements)
|
|
@@ -354,8 +406,6 @@ export default class extends Controller {
|
|
|
354
406
|
return
|
|
355
407
|
}
|
|
356
408
|
|
|
357
|
-
// Delegated on document so it keeps working after a parent advanced select
|
|
358
|
-
// rewrites its hidden input on each selection.
|
|
359
409
|
this.dependentChangeListener = (event) => {
|
|
360
410
|
if (event.target instanceof Element && this.dependentSelectors.some((selector) => event.target.matches(selector))) {
|
|
361
411
|
this.reloadDependentOptions()
|
|
@@ -385,13 +435,7 @@ export default class extends Controller {
|
|
|
385
435
|
return
|
|
386
436
|
}
|
|
387
437
|
|
|
388
|
-
|
|
389
|
-
this.selectOption(
|
|
390
|
-
option.dataset.advancedSelectValueParam,
|
|
391
|
-
option.dataset.advancedSelectLabelParam,
|
|
392
|
-
option.dataset.advancedSelectSubmitValueParam || option.dataset.advancedSelectValueParam,
|
|
393
|
-
{ displayLabel: option.dataset.advancedSelectDisplayLabelParam, refreshOptions: false }
|
|
394
|
-
)
|
|
438
|
+
this.selectOptionFromElement(options[0], { refreshOptions: false })
|
|
395
439
|
}
|
|
396
440
|
|
|
397
441
|
chooseActiveOption() {
|
|
@@ -403,12 +447,7 @@ export default class extends Controller {
|
|
|
403
447
|
this.activeOption.dataset.advancedSelectDisplayLabelParam
|
|
404
448
|
)
|
|
405
449
|
} else {
|
|
406
|
-
this.
|
|
407
|
-
this.activeOption.dataset.advancedSelectValueParam,
|
|
408
|
-
this.activeOption.dataset.advancedSelectLabelParam,
|
|
409
|
-
this.activeOption.dataset.advancedSelectSubmitValueParam || this.activeOption.dataset.advancedSelectValueParam,
|
|
410
|
-
{ displayLabel: this.activeOption.dataset.advancedSelectDisplayLabelParam }
|
|
411
|
-
)
|
|
450
|
+
this.selectOptionFromElement(this.activeOption)
|
|
412
451
|
}
|
|
413
452
|
}
|
|
414
453
|
|
|
@@ -528,10 +567,19 @@ export default class extends Controller {
|
|
|
528
567
|
}
|
|
529
568
|
|
|
530
569
|
renderTooltip() {
|
|
531
|
-
if (!this.hasTooltipTarget
|
|
570
|
+
if (!this.hasTooltipTarget) {
|
|
532
571
|
return
|
|
533
572
|
}
|
|
534
573
|
|
|
574
|
+
if (this.tooltipTarget.hasAttribute("data-advanced-select-tooltip-custom")) {
|
|
575
|
+
this.renderCustomTooltip()
|
|
576
|
+
return
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
this.renderBuiltInTooltip()
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
renderBuiltInTooltip() {
|
|
535
583
|
const list = this.tooltipTarget.querySelector("[data-advanced-select-tooltip-list]")
|
|
536
584
|
if (!list) {
|
|
537
585
|
return
|
|
@@ -546,6 +594,78 @@ export default class extends Controller {
|
|
|
546
594
|
}
|
|
547
595
|
}
|
|
548
596
|
|
|
597
|
+
renderCustomTooltip() {
|
|
598
|
+
const list = this.tooltipTarget.querySelector("[data-advanced-select-tooltip-list]")
|
|
599
|
+
const template = this.customTooltipTemplate()
|
|
600
|
+
|
|
601
|
+
if (!list || !template) {
|
|
602
|
+
if (this.selectedValue.length === 0) {
|
|
603
|
+
this.hideTooltip(true)
|
|
604
|
+
}
|
|
605
|
+
return
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
list.replaceChildren(
|
|
609
|
+
...this.selectedValue.map((option) => this.customTooltipElement(template, option))
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
if (this.selectedValue.length === 0) {
|
|
613
|
+
this.hideTooltip(true)
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
customTooltipTemplate() {
|
|
618
|
+
if (this.customTooltipTemplateContent) {
|
|
619
|
+
return this.customTooltipTemplateContent
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const template = this.tooltipTarget.querySelector("template[data-advanced-select-tooltip-template]")
|
|
623
|
+
if (!template) {
|
|
624
|
+
return null
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
this.customTooltipTemplateContent = template.content.cloneNode(true)
|
|
628
|
+
template.remove()
|
|
629
|
+
return this.customTooltipTemplateContent
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
customTooltipElement(template, option) {
|
|
633
|
+
const fragment = template.cloneNode(true)
|
|
634
|
+
fragment.querySelectorAll("[data-advanced-select-tooltip-field]").forEach((element) => {
|
|
635
|
+
element.textContent = this.tooltipFieldValue(option, element.dataset.advancedSelectTooltipField)
|
|
636
|
+
})
|
|
637
|
+
|
|
638
|
+
return fragment
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
tooltipFieldValue(option, field) {
|
|
642
|
+
if (field === "display_label" || field === "displayLabel") {
|
|
643
|
+
return this.displayLabel(option)
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const value = this.optionFieldValue(option, field)
|
|
647
|
+
return value === undefined || value === null ? "" : value.toString()
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
optionFieldValue(option, field) {
|
|
651
|
+
const directValue = option[field] ?? option[this.camelize(field)]
|
|
652
|
+
if (directValue !== undefined) {
|
|
653
|
+
return directValue
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return field.split(".").reduce((value, segment) => {
|
|
657
|
+
if (value === undefined || value === null) {
|
|
658
|
+
return undefined
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
return value[segment] ?? value[this.camelize(segment)]
|
|
662
|
+
}, option)
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
camelize(value) {
|
|
666
|
+
return value.replace(/_([a-z])/g, (_match, character) => character.toUpperCase())
|
|
667
|
+
}
|
|
668
|
+
|
|
549
669
|
textElement(tagName, className, text) {
|
|
550
670
|
const element = document.createElement(tagName)
|
|
551
671
|
element.className = className
|
|
@@ -581,4 +701,4 @@ export default class extends Controller {
|
|
|
581
701
|
get expanded() {
|
|
582
702
|
return this.triggerTarget.getAttribute("aria-expanded") === "true"
|
|
583
703
|
}
|
|
584
|
-
}
|
|
704
|
+
}
|