custom select to replace select-2
Some checks failed
Build and Push Docker Image / build (push) Failing after 7m5s
Some checks failed
Build and Push Docker Image / build (push) Failing after 7m5s
it's called 'corbz-select' because I suck at naming things
This commit is contained in:
parent
198d70d072
commit
5da1012718
@ -264,6 +264,12 @@ async function loadSubModalOptions($input, url) {
|
|||||||
|
|
||||||
// Re-enable input
|
// Re-enable input
|
||||||
$input.prop("disabled", false);
|
$input.prop("disabled", false);
|
||||||
|
|
||||||
|
// Re-init the component
|
||||||
|
if ($input.next('.corbz-select-container').length) {
|
||||||
|
$input.next('.corbz-select-container').remove();
|
||||||
|
$input.initCorbzSelect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel options aren't loaded from an API, like other options.
|
// Channel options aren't loaded from an API, like other options.
|
||||||
@ -288,6 +294,12 @@ async function loadChannelOptions() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
$input.prop("disabled", false);
|
$input.prop("disabled", false);
|
||||||
|
|
||||||
|
// Re-init the component
|
||||||
|
if ($input.next('.corbz-select-container').length) {
|
||||||
|
$input.next('.corbz-select-container').remove();
|
||||||
|
$input.initCorbzSelect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,3 +35,125 @@
|
|||||||
&:disabled, &.disabled { color: var(--bs-secondary-color) }
|
&:disabled, &.disabled { color: var(--bs-secondary-color) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Custom Select Component
|
||||||
|
|
||||||
|
.corbz-select {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.corbz-select-container {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||||
|
border-radius: var(--bs-border-radius-sm);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-radius: var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.corbz-select-selected {
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.corbz-select-dropdown {
|
||||||
|
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
width: calc(100% + 2.25px);
|
||||||
|
transform: translateX(-1px);
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
border: 1px solid var(--bs-border-color);
|
||||||
|
border-radius: 0 0 var(--bs-border-radius-sm) var(--bs-border-radius-sm);
|
||||||
|
box-shadow: var(--bs-box-shadow);
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
.corbz-select-search {
|
||||||
|
|
||||||
|
// display: none; // disabled for now
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid var(--bs-border-color);
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.corbz-select-option {
|
||||||
|
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover { background-color: var(--bs-tertiary-bg); }
|
||||||
|
&.active {
|
||||||
|
|
||||||
|
color: var(--bs-white);
|
||||||
|
background-color: var(--bs-primary);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-select versions
|
||||||
|
> .corbz-option-checkbox {
|
||||||
|
|
||||||
|
--bs-form-check-bg-image: none;
|
||||||
|
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
appearance: none;
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
background-image: var(--bs-form-check-bg-image);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
border: var(--bs-border-width) solid var(--bs-border-color);
|
||||||
|
border-radius: var(--bs-border-radius-sm);
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&:checked {
|
||||||
|
|
||||||
|
|
||||||
|
--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
|
||||||
|
background-color: var(--bs-primary);
|
||||||
|
border-color: var(--bs-primary);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-left: 0.75rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<div class="col-lg-6 pe-lg-4">
|
<div class="col-lg-6 pe-lg-4">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="subMessageStyle" class="form-label">Message Style</label>
|
<label for="subMessageStyle" class="form-label">Message Style</label>
|
||||||
<select name="subMessageStyle" id="subMessageStyle" class="select-2" data-field="message_style" data-default="firstOption" tabindex="3">
|
<select name="subMessageStyle" id="subMessageStyle" class="corbz-select" data-field="message_style" data-default="firstOption" tabindex="3">
|
||||||
</select>
|
</select>
|
||||||
<div class="form-text">Appearance of delivered content.</div>
|
<div class="form-text">Appearance of delivered content.</div>
|
||||||
</div>
|
</div>
|
||||||
@ -44,21 +44,21 @@
|
|||||||
<div class="col-lg-6 pe-lg-4">
|
<div class="col-lg-6 pe-lg-4">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="subChannels" class="form-label">Channels</label>
|
<label for="subChannels" class="form-label">Channels</label>
|
||||||
<select name="subChannels" id="subChannels" class="select-2" multiple data-field="channels" tabindex="5"></select>
|
<select name="subChannels" id="subChannels" class="corbz-select" multiple data-field="channels" tabindex="5"></select>
|
||||||
<div class="form-text">Send content to these channels.</div>
|
<div class="form-text">Send content to these channels.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 ps-lg-4">
|
<div class="col-lg-6 ps-lg-4">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="subFilters" class="form-label">Filters</label>
|
<label for="subFilters" class="form-label">Filters</label>
|
||||||
<select name="subFilters" id="subFilters" class="select-2" multiple data-field="filters" tabindex="6"></select>
|
<select name="subFilters" id="subFilters" class="corbz-select" multiple data-field="filters" tabindex="6"></select>
|
||||||
<div class="form-text">Filter out unwanted content.</div>
|
<div class="form-text">Filter out unwanted content.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 pe-lg-4">
|
<div class="col-lg-6 pe-lg-4">
|
||||||
<div class="mb-4 mb-lg-0">
|
<div class="mb-4 mb-lg-0">
|
||||||
<label for="subUniqueRules" class="form-label">Uniqueness Rules</label>
|
<label for="subUniqueRules" class="form-label">Uniqueness Rules</label>
|
||||||
<select name="subUniqueRules" id="subUniqueRules" class="select-2" multiple required data-field="unique_rules" tabindex="7"></select>
|
<select name="subUniqueRules" id="subUniqueRules" class="corbz-select" multiple required data-field="unique_rules" tabindex="7"></select>
|
||||||
<div class="form-text">Rules on telling content apart.</div>
|
<div class="form-text">Rules on telling content apart.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,6 +82,10 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".corbz-select").each(function() {
|
||||||
|
$(this).initCorbzSelect();
|
||||||
|
});
|
||||||
|
|
||||||
$.notify.addStyle("bootstrap", {
|
$.notify.addStyle("bootstrap", {
|
||||||
html:
|
html:
|
||||||
'<div class="toast mt-3 overflow-hidden" role="alert">' +
|
'<div class="toast mt-3 overflow-hidden" role="alert">' +
|
||||||
@ -102,4 +106,166 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
// Load theme
|
// Load theme
|
||||||
initThemeChoice();
|
initThemeChoice();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Custom Select Jquery
|
||||||
|
(($) => {
|
||||||
|
function initCorbzSelect() {
|
||||||
|
const defaultSelectedHtml = " ";
|
||||||
|
|
||||||
|
const updateSelectedDisplay = ($select, $selected, $dropdown, settings) => {
|
||||||
|
const values = $select.val() || [];
|
||||||
|
const names = [];
|
||||||
|
|
||||||
|
// Update names based on values
|
||||||
|
$select.find("option").each(function() {
|
||||||
|
if (values.includes($(this).val())) {
|
||||||
|
names.push($(this).text());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(JSON.stringify(names))
|
||||||
|
|
||||||
|
const len = values.length;
|
||||||
|
const total = $select.find("option").length;
|
||||||
|
|
||||||
|
if (len === 0) { $selected.html(defaultSelectedHtml); }
|
||||||
|
else if (len === total) {$selected.text("All Selected")}
|
||||||
|
else if (len > 3) { $selected.text(`${values.length} Selected`); }
|
||||||
|
else { $selected.text(names.join(", ")); }
|
||||||
|
|
||||||
|
if (!settings.multiple) {
|
||||||
|
$dropdown.find(".corbz-select-option").removeClass("active").each(function() {
|
||||||
|
if (names.includes($(this).data("name"))) {
|
||||||
|
$(this).addClass("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$dropdown.find(".corbz-option-checkbox").each(function() {
|
||||||
|
$(this).prop("checked", values.includes($(this).val()));
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.each(function() {
|
||||||
|
// The original select element, this will be hidden and replaced
|
||||||
|
// with the custom input 'container'
|
||||||
|
const $select = $(this);
|
||||||
|
|
||||||
|
// The custom input to replace the original select
|
||||||
|
const $container = $('<div class="corbz-select-container">');
|
||||||
|
|
||||||
|
// Contains text indicating the 'selected' options, acts as a
|
||||||
|
// button to open the dropdown.
|
||||||
|
const $selected = $('<div class="corbz-select-selected">');
|
||||||
|
$selected.html(defaultSelectedHtml);
|
||||||
|
|
||||||
|
// The dropdown box when accessing the container
|
||||||
|
const $dropdown = $('<div class="corbz-select-dropdown">');
|
||||||
|
|
||||||
|
// Search input to filter the dropdown results
|
||||||
|
const $search = $('<input type="text" class="corbz-select-search" placeholder="Search ...">');
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
id: $select.prop("id"),
|
||||||
|
multiple: $select.prop("multiple"),
|
||||||
|
required: $select.prop("required"),
|
||||||
|
disabled: $select.prop("disabled"),
|
||||||
|
minResultsForSearch: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add custom elements to the DOM
|
||||||
|
$dropdown.prepend($search);
|
||||||
|
$container.append($selected).append($dropdown);
|
||||||
|
$select.hide().after($container);
|
||||||
|
|
||||||
|
// Show/Hide the dropdown when clicking the custom input
|
||||||
|
$selected.on("click", function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
$('.corbz-select-dropdown').not($dropdown).hide();
|
||||||
|
$dropdown.toggle();
|
||||||
|
$container.toggleClass("active", $dropdown.is(":visible"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide dropdown if clicking outside
|
||||||
|
$(document).on('click', function() {
|
||||||
|
$dropdown.hide();
|
||||||
|
$container.removeClass("active");
|
||||||
|
|
||||||
|
// Reset search filtering
|
||||||
|
$search.val("");
|
||||||
|
$search.trigger("keyup");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use or hide search
|
||||||
|
$search.toggle($select.find("option").length > settings.minResultsForSearch);
|
||||||
|
|
||||||
|
// Prevent closing the dropdown when selecting the search input
|
||||||
|
$search.on("click", function (event) { event.stopPropagation(); });
|
||||||
|
|
||||||
|
// Search to filter through options
|
||||||
|
$search.on("keyup", function () {
|
||||||
|
const searchValue = $(this).val().toLowerCase();
|
||||||
|
$dropdown.find(".corbz-select-option").each(function() {
|
||||||
|
const optionText = $(this).text().toLowerCase();
|
||||||
|
$(this).toggle(optionText.includes(searchValue))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateSelectedDisplayWrapper = () => {
|
||||||
|
updateSelectedDisplay($select, $selected, $dropdown, settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
$select.find("option").each(function() {
|
||||||
|
const $option = $('<div class="corbz-select-option">');
|
||||||
|
$option.data("name", $(this).text());
|
||||||
|
$option.data("value", $(this).val());
|
||||||
|
|
||||||
|
if (!settings.multiple) {
|
||||||
|
$option.text($(this).text());
|
||||||
|
$option.on("click", function() {
|
||||||
|
$dropdown.hide();
|
||||||
|
$container.removeClass("active");
|
||||||
|
$select.val($option.data("value"));
|
||||||
|
updateSelectedDisplayWrapper();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const $checkbox = $(`<input type="checkbox" name="${settings.id}" class="corbz-option-checkbox" value="${$(this).val()}">`).val($(this).val());
|
||||||
|
const $label = $("<span>").text($(this).text());
|
||||||
|
$option.prepend($checkbox).append($label);
|
||||||
|
$option.on("click", function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
// Handle if the user clicked inside the checkbox itself
|
||||||
|
if (!$(event.target).hasClass("corbz-option-checkbox")) {
|
||||||
|
$checkbox.prop("checked", !$checkbox.prop("checked"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedElems = $dropdown.find(`input[type="checkbox"][name="${settings.id}"]:checked`).map(function() {
|
||||||
|
return $(this).closest(".corbz-select-option");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get and internally set the selected values
|
||||||
|
const selectedVals = selectedElems.map(function() {
|
||||||
|
return this.data("value");
|
||||||
|
});
|
||||||
|
$select.val(selectedVals).trigger("change");
|
||||||
|
|
||||||
|
updateSelectedDisplayWrapper();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$dropdown.append($option)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize display, and detect future changes
|
||||||
|
updateSelectedDisplayWrapper();
|
||||||
|
$select.on("change", updateSelectedDisplayWrapper);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.initCorbzSelect = initCorbzSelect;
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user