Skip to content

Commit

Permalink
wc: improve select-field-filter2 selection #TASK-5070
Browse files Browse the repository at this point in the history
  • Loading branch information
Rodielm committed Oct 23, 2023
1 parent 583a87c commit 9537653
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 74 deletions.
8 changes: 5 additions & 3 deletions src/webcomponents/commons/catalog-browser-grid-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,11 @@ export default class CatalogBrowserGridConfig extends LitElement {
<select-field-filter2
.data="${this.selectColumnData}"
.value="${this.selectedColumns?.join(",")}"
.title="${"Columns"}"
.multiple="${true}"
.classes="${"btn-sm"}"
.config="${{
title: "Columns",
tags: false,
liveSearch: false,
}}"
@filterChange="${e => dataFormFilterChange(e.detail.value)}">
</select-field-filter2>
`;
Expand Down
14 changes: 8 additions & 6 deletions src/webcomponents/commons/filters/disease-panel-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import {LitElement, html, nothing} from "lit";
import LitUtils from "../utils/lit-utils.js";
import "../forms/select-field-filter.js";
import "../forms/select-field-filter2.js";
import "../forms/toggle-switch.js";
import "../forms/toggle-radio.js";

Expand Down Expand Up @@ -210,16 +211,17 @@ export default class DiseasePanelFilter extends LitElement {
</label>
` : nothing
}
<select-field-filter
<select-field-filter2
.data="${this.diseasePanelsSelectOptions}"
.value=${this.panel}
.liveSearch=${this.diseasePanelsSelectOptions?.length > 5}
.multiple="${this.multiple || false}"
.classes="${this.classes}"
.disabled="${this.disabled || false}"
separator="\n"
.config="${{
tags: false,
multiple: this.multiple,
separator: "\n"
}}"
@filterChange="${e => this.filterChange(e, "panel")}">
</select-field-filter>
</select-field-filter2>
</div>
${this.showSelectedPanels && this.panel?.length > 0 ? html`
Expand Down
256 changes: 194 additions & 62 deletions src/webcomponents/commons/forms/select-field-filter2.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,71 +37,43 @@ export default class SelectFieldFilter2 extends LitElement {
value: {
type: String
},
title: {
type: String
},
placeholder: {
type: String
},
multiple: {
type: Boolean
},
all: {
type: Boolean
},
disabled: {
type: Boolean
},
required: {
type: Boolean
},
maxOptions: {
type: Number
},
liveSearch: {
type: Boolean
},
forceSelection: {
type: Boolean
},
classes: {
type: String
},
size: {
type: Number,
},
separator: {
type: String,
},
// the expected format is either an array of string or an array of objects {id, name}
data: {
type: Object
},
config: {
type: Object
}
};
}

_init() {
this._prefix = UtilsNew.randomString(8);
// $.fn.selectpicker.Constructor.BootstrapVersion = "5";
this.multiple = false;
this.all = false;
this.data = [];
this.classes = "";
this.elm = this._prefix + "selectpicker";
this.size = 20; // Default size
this.separator = ","; // Default separator
}

firstUpdated() {
this.select = $("#" + this._prefix);
if (!this._config?.tags) {
this.customAdapter();
}
}

update(changedProperties) {
if (changedProperties.has("config")) {
this._config = {...this.getDefaultConfig(), ...this.config};
}
super.update(changedProperties);
}

updated(changedProperties) {
if (changedProperties.has("data")) {
this.loadData();
}

if (changedProperties.has("value") || changedProperties.has("disabled")) {
if (changedProperties.has("value")) {
// TODO: Figure out why this does not execute when config.tags are false.
this.loadValueSelected();
}
}
Expand All @@ -124,42 +96,167 @@ export default class SelectFieldFilter2 extends LitElement {
});
}
});
this.select.select2({
const selectConfig = {
theme: "bootstrap-5",
dropdownParent: document.querySelector(`#${this._prefix}`).parentElement,
selectionCssClass: "select2--small",
tags: this._config?.freeTag ?? false,
multiple: this.multiple,
separator: this.separator,
placeholder: this.placeholder || "Select option(s)",
disabled: this.disabled,
multiple: this._config?.multiple,
placeholder: this._config?.placeholder,
disabled: false,
width: "80%",
data: options,
tokenSeparator: this.tokenSeparator,
selectOnClose: false,
tokenSeparator: this._config?.separator,
closeOnSelect: false,
templateResult: e => this.optionsFormatter(e),
})
.on("select2:select", e => this.filterChange(e))
.on("select2:unselect", e => this.filterChange(e));
...this._config,
};

if (!this._config?.tags) {
const searchBox = {dropdownAdapter: $.fn.select2.amd.require("CustomDropdownAdapter")};
const selectAdapter = {
templateSelection: data => {
return `Selected ${data.selected.length} out of ${data.all.length}`;
},
// Make selection-box similar to single select
selectionAdapter: $.fn.select2.amd.require("CustomSelectionAdapter"),
...this._config.liveSearch ? searchBox : {}
};

this.select.select2({...selectConfig, ...selectAdapter})
.on("select2:select", e => this.filterChange(e))
.on("select2:unselect", e => this.filterChange(e));

if (this.value) {
// temporal solution for now to load selected values
this.loadValueSelected();
}

} else {
this.select.select2({...selectConfig})
.on("select2:select", e => this.filterChange(e))
.on("select2:unselect", e => this.filterChange(e));

}

this.querySelector("span.select2-search.select2-search--inline").style = "display: none";
// This hides the search field for basic select2 tags.
if (!this.config?.liveSearch && !this.config?.tags) {
this.querySelector("span.select2-search select2-search--dropdown").style.display = "none";
}
}
}

customAdapter() {

$.fn.select2.amd.define("CustomSelectionAdapter", [
"select2/utils",
"select2/selection/multiple",
"select2/selection/placeholder",
"select2/selection/eventRelay",
"select2/selection/single",
], (Utils, MultipleSelection, Placeholder, EventRelay, SingleSelection) => {

// Decorates MultipleSelection with Placeholder
let adapter = Utils.Decorate(MultipleSelection, Placeholder);
// Decorates adapter with EventRelay - ensures events will continue to fire
// e.g. selected, changed
adapter = Utils.Decorate(adapter, EventRelay);

adapter.prototype.render = function () {
// Use selection-box from SingleSelection adapter
// This implementation overrides the default implementation
const $selection = SingleSelection.prototype.render.call(this);
return $selection;
};

adapter.prototype.update = function (data) {
// copy and modify SingleSelection adapter
this.clear();

const $rendered = this.$selection.find(".select2-selection__rendered");
const noItemsSelected = data.length === 0;
let formatted = "";

if (noItemsSelected) {
formatted = this.options.get("placeholder") || "";
} else {
const itemsData = {
selected: data || [],
all: this.$element.find("option") || []
};
// Pass selected and all items to display method
// which calls templateSelection
formatted = this.display(itemsData, $rendered);
}

$rendered.empty().append(formatted);
$rendered.prop("title", formatted);
};

return adapter;
});

$.fn.select2.amd.define("CustomDropdownAdapter", [
"select2/utils",
"select2/dropdown",
"select2/dropdown/attachBody",
"select2/dropdown/attachContainer",
"select2/dropdown/search",
"select2/dropdown/minimumResultsForSearch",
"select2/dropdown/closeOnSelect",
], (Utils, Dropdown, AttachBody, AttachContainer, Search, MinimumResultsForSearch, CloseOnSelect) => {

// Decorate Dropdown with Search functionalities
const dropdownWithSearch = Utils.Decorate(Dropdown, Search);
dropdownWithSearch.prototype.render = function () {
// Copy and modify default search render method
const $rendered = Dropdown.prototype.render.call(this);
// Add ability for a placeholder in the search box
const placeholder = this.options.get("placeholderForSearch") || "";
const $search = $(
`<span class="select2-search select2-search--dropdown">
<input class="select2-search__field" placeholder="${placeholder}" type="search"
tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off"
spellcheck="false" role="textbox"/>
</span>`
);

this.$searchContainer = $search;
this.$search = $search.find("input");

$rendered.prepend($search);
return $rendered;
};

// Decorate the dropdown+search with necessary containers
let adapter = Utils.Decorate(dropdownWithSearch, AttachContainer);
adapter = Utils.Decorate(adapter, AttachBody);

return adapter;
});

}

optionsFormatter(item) {
// optgroup elements
if (typeof item.children != "undefined") {
return $(`
<span class='fw-bold fs-6 text-dark'>${item.text}</span>
<hr class="m-0 mb-2"/>
<span class='fw-bold text-secondary'>
<small>${item.text}</small>
</span>
`);
}
return $(`
<small>${item.text}</small>
<div class="d-flex justify-content-between align-items-center py-1">
<span>${item.text}</span>
<i class="fas fa-check d-none"></i>
</div>
`);
}

loadValueSelected() {
let val = "";
if (this.value && this.multiple) {
if (this.value && this._config?.multiple) {
val = Array.isArray(this.value) ? this.value : this.value.split(",");
} else {
val = UtilsNew.isNotUndefinedOrNull(this.value) ? this.value : "";
Expand Down Expand Up @@ -192,7 +289,7 @@ export default class SelectFieldFilter2 extends LitElement {

let val = "";
if (selection && selection.length) {
if (this.multiple) {
if (this._config?.multiple) {
val = selection.join(",");
}
}
Expand Down Expand Up @@ -229,13 +326,34 @@ export default class SelectFieldFilter2 extends LitElement {
`;
}

renderStyle() {
return html`
<style>
.select-field-filter .select2-results__option--selected {
background-color: #fff !important;
color: #000 !important;
}
.select-field-filter .select2-results__option--selected:hover {
background-color: #e9ecef !important;
}
.select-field-filter .select2-results__option--selected i.fa-check {
display: inline-block !important;
}
.select-field-filter .select2-results__group {
display: block;
padding: 6px 4px !important;
}
</style>
`;
}

render() {
return html`
<div class="input-group mb-1">
${this.renderStyle()}
<div class="input-group mb-1 select-field-filter">
<select
class="form-select"
id="${this._prefix}"
?disabled="${this.disabled}"
@change="${this.filterChange}">
</select>
${this.all ? this.renderShowSelectAll() : nothing}
Expand All @@ -244,7 +362,21 @@ export default class SelectFieldFilter2 extends LitElement {

getDefaultConfig() {
return {

title: "",
separator: [","],
multiple: true,
all: false,
required: false,
liveSearch: true,
classes: "",
showSelectAll: false,
limit: 10,
disablePagination: false,
minimumInputLength: 0,
maxItems: 0, // maxOptions
disabled: false,
placeholder: "Select option(s)",
freeTag: false
};
}

Expand Down
Loading

0 comments on commit 9537653

Please sign in to comment.