make card_multiselect DRY, closes #26
This commit is contained in:
parent
afaa392b2f
commit
10386b1ce9
6 changed files with 311 additions and 310 deletions
|
|
@ -11,62 +11,6 @@
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
select.card-multiselect {
|
|
||||||
height: calc(var(--spacing) * 35);
|
|
||||||
/*background-image: linear-gradient(45deg, #0000 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, #0000 50%); */
|
|
||||||
background-image: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices.is-disabled .choices__inner,
|
|
||||||
.choices.is-disabled .choices__input {
|
|
||||||
background-color: var(--color-neutral);
|
|
||||||
}
|
|
||||||
.choices[data-type*=select-one] .choices__input {
|
|
||||||
border-bottom: 1px solid var(--btn-shadow);
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
}
|
|
||||||
.choices[data-type*=select-one] .choices__button:focus {
|
|
||||||
box-shadow: 0 0 0 2px #005F75;
|
|
||||||
}
|
|
||||||
.choices__inner {
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
border: 1px solid var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.is-focused .choices__inner, .is-open .choices__inner {
|
|
||||||
border-color: var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.choices__list--multiple .choices__item {
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
border: 1px solid var(--btn-shadow);
|
|
||||||
color: var(--color-primary);
|
|
||||||
}
|
|
||||||
.choices__list--multiple .choices__item.is-highlighted {
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
border: 1px solid var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.is-disabled .choices__list--multiple .choices__item {
|
|
||||||
background-color: var(--color-neutral);
|
|
||||||
border: 1px solid var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.choices__list--dropdown, .choices__list[aria-expanded] {
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
border: 1px solid var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {
|
|
||||||
border-color: var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
border: 1px solid var(--btn-shadow);
|
|
||||||
}
|
|
||||||
.choices__heading {
|
|
||||||
border-bottom: 1px solid var(--btn-shadow);
|
|
||||||
color: var(--color-neutral);
|
|
||||||
}
|
|
||||||
.choices__input {
|
|
||||||
background-color: var(--color-base-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gravatar-hovercard .gravatar-hovercard__inner {
|
.gravatar-hovercard .gravatar-hovercard__inner {
|
||||||
background-color: var(--color-base-100) !important;
|
background-color: var(--color-base-100) !important;
|
||||||
border-color: var(--color-base-300) !important;
|
border-color: var(--color-base-300) !important;
|
||||||
|
|
|
||||||
88
static/css/card-multiselect.css
Normal file
88
static/css/card-multiselect.css
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
select.card-multiselect {
|
||||||
|
height: calc(var(--spacing) * 35);
|
||||||
|
/*background-image: linear-gradient(45deg, #0000 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, #0000 50%); */
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.choices.is-disabled .choices__inner,
|
||||||
|
.choices.is-disabled .choices__input {
|
||||||
|
background-color: var(--color-neutral);
|
||||||
|
}
|
||||||
|
.choices[data-type*=select-one] .choices__input {
|
||||||
|
border-bottom: 1px solid var(--btn-shadow);
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
}
|
||||||
|
.choices[data-type*=select-one] .choices__button:focus {
|
||||||
|
box-shadow: 0 0 0 2px #005F75;
|
||||||
|
}
|
||||||
|
.choices__inner {
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
border: 1px solid var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.is-focused .choices__inner, .is-open .choices__inner {
|
||||||
|
border-color: var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.choices__list--multiple .choices__item {
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
border: 1px solid var(--btn-shadow);
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
.choices__list--multiple .choices__item.is-highlighted {
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
border: 1px solid var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.is-disabled .choices__list--multiple .choices__item {
|
||||||
|
background-color: var(--color-neutral);
|
||||||
|
border: 1px solid var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.choices__list--dropdown, .choices__list[aria-expanded] {
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
border: 1px solid var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {
|
||||||
|
border-color: var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
border: 1px solid var(--btn-shadow);
|
||||||
|
}
|
||||||
|
.choices__heading {
|
||||||
|
border-bottom: 1px solid var(--btn-shadow);
|
||||||
|
color: var(--color-neutral);
|
||||||
|
}
|
||||||
|
.choices__input {
|
||||||
|
background-color: var(--color-base-100);
|
||||||
|
}
|
||||||
|
.choices.select {
|
||||||
|
height: inherit;
|
||||||
|
padding-inline-start: 0;
|
||||||
|
}
|
||||||
|
.choices__inner {
|
||||||
|
border: 1px solid var(--color-gray-500) !important;
|
||||||
|
}
|
||||||
|
.choices__list {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.choices__list--dropdown {
|
||||||
|
border-left: 1px solid var(--color-gray-500) !important;
|
||||||
|
border-right: 1px solid var(--color-gray-500) !important;
|
||||||
|
border-bottom: 1px solid var(--color-gray-500) !important;
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
.choices.select[data-type*="select-one"]::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.choices__inner.bg-secondary {
|
||||||
|
background-color: var(--color-secondary);
|
||||||
|
border: none;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.choices__item.mx-auto.w-max:hover {
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
}
|
||||||
|
.choices__input,
|
||||||
|
.choices__input--cloned {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.choices__list--dropdown span.card-quantity-badge {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -119,7 +119,6 @@ const $$ = selector => Array.from(document.querySelector(selector));
|
||||||
*/
|
*/
|
||||||
function processMarqueeElements() {
|
function processMarqueeElements() {
|
||||||
document.querySelectorAll('.marquee-calc').forEach(element => {
|
document.querySelectorAll('.marquee-calc').forEach(element => {
|
||||||
console.log(element.innerHTML, element.offsetWidth, element.scrollWidth);
|
|
||||||
if (element.offsetWidth >= 148 || element.offsetWidth < element.scrollWidth) {
|
if (element.offsetWidth >= 148 || element.offsetWidth < element.scrollWidth) {
|
||||||
element.innerHTML = '<marquee behavior="scroll" direction="left" scrolldelay="80">' + element.innerHTML + '</marquee>';
|
element.innerHTML = '<marquee behavior="scroll" direction="left" scrolldelay="80">' + element.innerHTML + '</marquee>';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
219
static/js/card-multiselect.js
Normal file
219
static/js/card-multiselect.js
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
if (!window.updateGlobalCardFilters) {
|
||||||
|
window.updateGlobalCardFilters = function() {
|
||||||
|
const selects = document.querySelectorAll('.card-multiselect');
|
||||||
|
|
||||||
|
// Rebuild global selections and rarity filtering.
|
||||||
|
const globalSelectedIds = [];
|
||||||
|
let globalRarity = null;
|
||||||
|
|
||||||
|
selects.forEach(select => {
|
||||||
|
const selectedValues = select.choicesInstance ? select.choicesInstance.getValue(true) : [];
|
||||||
|
selectedValues.forEach(cardId => {
|
||||||
|
if (cardId && globalSelectedIds.indexOf(cardId) === -1) {
|
||||||
|
globalSelectedIds.push(cardId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (selectedValues.length > 0 && globalRarity === null) {
|
||||||
|
const option = select.querySelector('option[value="${selectedValues[0]}"]');
|
||||||
|
if (option) {
|
||||||
|
globalRarity = option.getAttribute('data-rarity');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
selects.forEach(select => {
|
||||||
|
if (select.choicesInstance && select.choicesInstance.dropdown.element) {
|
||||||
|
// Reset all options to enabled.
|
||||||
|
select.querySelectorAll('option').forEach(function(option) {
|
||||||
|
option.disabled = false;
|
||||||
|
});
|
||||||
|
// Reset all items to visible.
|
||||||
|
select.choicesInstance.dropdown.element.querySelectorAll('[data-card-id]').forEach(function(item) {
|
||||||
|
item.style.display = '';
|
||||||
|
});
|
||||||
|
// Filter out options/items that do not match the global rarity.
|
||||||
|
if (globalRarity) {
|
||||||
|
select.querySelectorAll('option[data-rarity]:not([data-rarity="'+globalRarity+'"])').forEach(function(option) {
|
||||||
|
option.disabled = true;
|
||||||
|
});
|
||||||
|
select.choicesInstance.dropdown.element.querySelectorAll('[data-rarity]:not([data-rarity="'+globalRarity+'"])').forEach(function(item) {
|
||||||
|
item.style.display = 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Filter out options/items that match the global selected card IDs.
|
||||||
|
for (const cardId of globalSelectedIds) {
|
||||||
|
select.choicesInstance.dropdown.element.querySelectorAll('[data-card-id="' + cardId + '"]').forEach(function(item) {
|
||||||
|
item.style.display = 'none';
|
||||||
|
});
|
||||||
|
select.querySelectorAll('option[data-card-id="'+cardId+'"]:not(option[selected])').forEach(function(option) {
|
||||||
|
option.disabled = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.updateOptionQuantity) {
|
||||||
|
window.updateOptionQuantity = function(item, quantity) {
|
||||||
|
const cardId = item.getAttribute('data-card-id');
|
||||||
|
const option = item.closest('.choices__inner').querySelector('option[value="' + cardId + '"]');
|
||||||
|
if (option) {
|
||||||
|
option.setAttribute('data-quantity', quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.getOptionQuantity) {
|
||||||
|
window.getOptionQuantity = function(item) {
|
||||||
|
const cardId = item.getAttribute('data-card-id');
|
||||||
|
const option = item.closest('.choices__inner').querySelector('option[value="' + cardId + '"]');
|
||||||
|
return option ? parseInt(option.getAttribute('data-quantity')) : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const selectFields = document.querySelectorAll('.card-multiselect');
|
||||||
|
selectFields.forEach(selectField => {
|
||||||
|
const placeholder = selectField.getAttribute('data-placeholder') || '';
|
||||||
|
|
||||||
|
const choicesInstance = new Choices(selectField, {
|
||||||
|
removeItemButton: false,
|
||||||
|
placeholderValue: placeholder,
|
||||||
|
searchEnabled: true,
|
||||||
|
shouldSort: false,
|
||||||
|
allowHTML: true,
|
||||||
|
closeDropdownOnSelect: true,
|
||||||
|
removeItemButton: true,
|
||||||
|
searchFields: ['label'],
|
||||||
|
resetScrollPosition: false,
|
||||||
|
callbackOnCreateTemplates: function(template) {
|
||||||
|
const getCardContent = (data) => {
|
||||||
|
let htmlContent = (data.element && data.element.getAttribute('data-html-content')) || data.label;
|
||||||
|
let quantity = data.element.getAttribute('data-quantity');
|
||||||
|
quantity = quantity ? parseInt(quantity) : 1;
|
||||||
|
htmlContent = htmlContent.replace('__QUANTITY__', quantity);
|
||||||
|
return htmlContent;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCard = (classNames, data, type) => {
|
||||||
|
const rarity = data.element ? data.element.getAttribute('data-rarity') : '';
|
||||||
|
const cardId = data.element ? data.element.getAttribute('data-card-id') : 0;
|
||||||
|
const cardname = data.element ? data.element.getAttribute('data-name') : '';
|
||||||
|
const content = getCardContent(data);
|
||||||
|
if (type === 'item') {
|
||||||
|
return template(`
|
||||||
|
<div class="${classNames.item} mx-auto w-max ${data.highlighted ? classNames.highlightedState : ''} relative"
|
||||||
|
data-id="${data.id}"
|
||||||
|
data-card-id="${cardId}"
|
||||||
|
data-item
|
||||||
|
data-rarity="${rarity}"
|
||||||
|
data-name="${cardname}"
|
||||||
|
aria-selected="true"
|
||||||
|
style="cursor: pointer; padding: 1rem;">
|
||||||
|
<button type="button" class="decrement absolute left-[-1.5rem] top-1/2 transform -translate-y-1/2 bg-base-300 text-base-content px-2">-</button>
|
||||||
|
<button type="button" class="increment absolute right-[-1.5rem] top-1/2 transform -translate-y-1/2 bg-base-300 text-base-content px-2">+</button>
|
||||||
|
<div class="card-content">${content}</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
const extraAttributes = `data-select-text="${this.config.itemSelectText}" data-choice ${
|
||||||
|
data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'
|
||||||
|
}`;
|
||||||
|
const extraClasses = classNames.itemChoice;
|
||||||
|
return template(`
|
||||||
|
<div class="${classNames.item} ${extraClasses} ${data.highlighted ? classNames.highlightedState : ''} mx-auto w-max"
|
||||||
|
${extraAttributes}
|
||||||
|
data-id="${data.id}"
|
||||||
|
data-card-id="${cardId}"
|
||||||
|
data-name="${cardname}"
|
||||||
|
data-choice
|
||||||
|
data-rarity="${rarity}"
|
||||||
|
style="cursor: pointer;">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
choice: function(classNames, data) {
|
||||||
|
return renderCard(classNames, data, 'choice');
|
||||||
|
},
|
||||||
|
item: function(classNames, data) {
|
||||||
|
return renderCard(classNames, data, 'item');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Associate the Choices instance with the select field.
|
||||||
|
selectField.choicesInstance = choicesInstance;
|
||||||
|
|
||||||
|
if (!window.cardMultiselectInstances) {
|
||||||
|
window.cardMultiselectInstances = [];
|
||||||
|
}
|
||||||
|
window.cardMultiselectInstances.push(selectField);
|
||||||
|
|
||||||
|
selectField.addEventListener('change', function() {
|
||||||
|
if (window.updateGlobalCardFilters) {
|
||||||
|
window.updateGlobalCardFilters();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Listen for increment/decrement clicks (scoped to the choices container).
|
||||||
|
const choicesContainer = selectField.closest('.choices') || document;
|
||||||
|
|
||||||
|
choicesContainer.addEventListener('click', function(e) {
|
||||||
|
if (e.target.classList.contains('increment')) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
const container = e.target.closest('[data-item]');
|
||||||
|
if (container) {
|
||||||
|
let quantityBadge = container.querySelector('.card-quantity-badge');
|
||||||
|
let quantity = window.getOptionQuantity(container);
|
||||||
|
quantity = quantity + 1;
|
||||||
|
quantityBadge.innerText = quantity;
|
||||||
|
window.updateOptionQuantity(container, quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.target.classList.contains('decrement')) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
const container = e.target.closest('[data-item]');
|
||||||
|
if (container) {
|
||||||
|
let quantityBadge = container.querySelector('.card-quantity-badge');
|
||||||
|
let quantity = window.getOptionQuantity(container);
|
||||||
|
const cardId = container.getAttribute('data-card-id');
|
||||||
|
if (quantity === 1) {
|
||||||
|
const option = selectField.querySelector('option[value="' + cardId + '"]');
|
||||||
|
if (option) {
|
||||||
|
choicesInstance.removeActiveItemsByValue(option.value);
|
||||||
|
option.selected = false;
|
||||||
|
}
|
||||||
|
if (window.updateGlobalCardFilters) {
|
||||||
|
window.updateGlobalCardFilters();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quantity = quantity - 1;
|
||||||
|
quantityBadge.innerText = quantity;
|
||||||
|
window.updateOptionQuantity(container, quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.target.closest('[data-item]') &&
|
||||||
|
!e.target.classList.contains('increment') &&
|
||||||
|
!e.target.classList.contains('decrement')) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (choicesInstance.getValue(true).length > 0 && window.updateGlobalCardFilters) {
|
||||||
|
window.updateGlobalCardFilters();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -41,6 +41,9 @@
|
||||||
<script src="{% static 'js/floating-ui_core@1.6.9.9.min.js' %}"></script>
|
<script src="{% static 'js/floating-ui_core@1.6.9.9.min.js' %}"></script>
|
||||||
<script src="{% static 'js/floating-ui_dom@1.6.13.13.min.js' %}"></script>
|
<script src="{% static 'js/floating-ui_dom@1.6.13.13.min.js' %}"></script>
|
||||||
|
|
||||||
|
<script defer src="{% static 'js/card-multiselect.js' %}"></script>
|
||||||
|
<link rel="stylesheet" href="{% static 'css/card-multiselect.css' %}">
|
||||||
|
|
||||||
<script src="{% static 'js/base.js' %}"></script>
|
<script src="{% static 'js/base.js' %}"></script>
|
||||||
|
|
||||||
{% block css %}{% endblock %}
|
{% block css %}{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -20,255 +20,3 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endcache %}
|
{% endcache %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<script defer>
|
|
||||||
if (!window.updateGlobalCardFilters) {
|
|
||||||
window.updateGlobalCardFilters = function() {
|
|
||||||
const selects = document.querySelectorAll('.card-multiselect');
|
|
||||||
|
|
||||||
// Rebuild global selections and rarity filtering.
|
|
||||||
const globalSelectedIds = [];
|
|
||||||
let globalRarity = null;
|
|
||||||
|
|
||||||
selects.forEach(select => {
|
|
||||||
const selectedValues = select.choicesInstance ? select.choicesInstance.getValue(true) : [];
|
|
||||||
selectedValues.forEach(cardId => {
|
|
||||||
if (cardId && globalSelectedIds.indexOf(cardId) === -1) {
|
|
||||||
globalSelectedIds.push(cardId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (selectedValues.length > 0 && globalRarity === null) {
|
|
||||||
const option = select.querySelector('option[value="${selectedValues[0]}"]');
|
|
||||||
if (option) {
|
|
||||||
globalRarity = option.getAttribute('data-rarity');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
selects.forEach(select => {
|
|
||||||
if (select.choicesInstance && select.choicesInstance.dropdown.element) {
|
|
||||||
// Reset all options to enabled.
|
|
||||||
select.querySelectorAll('option').forEach(function(option) {
|
|
||||||
option.disabled = false;
|
|
||||||
});
|
|
||||||
// Reset all items to visible.
|
|
||||||
select.choicesInstance.dropdown.element.querySelectorAll('[data-card-id]').forEach(function(item) {
|
|
||||||
item.style.display = '';
|
|
||||||
});
|
|
||||||
// Filter out options/items that do not match the global rarity.
|
|
||||||
if (globalRarity) {
|
|
||||||
select.querySelectorAll('option[data-rarity]:not([data-rarity="'+globalRarity+'"])').forEach(function(option) {
|
|
||||||
option.disabled = true;
|
|
||||||
});
|
|
||||||
select.choicesInstance.dropdown.element.querySelectorAll('[data-rarity]:not([data-rarity="'+globalRarity+'"])').forEach(function(item) {
|
|
||||||
item.style.display = 'none';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Filter out options/items that match the global selected card IDs.
|
|
||||||
for (const cardId of globalSelectedIds) {
|
|
||||||
select.choicesInstance.dropdown.element.querySelectorAll('[data-card-id="' + cardId + '"]').forEach(function(item) {
|
|
||||||
item.style.display = 'none';
|
|
||||||
});
|
|
||||||
select.querySelectorAll('option[data-card-id="'+cardId+'"]:not(option[selected])').forEach(function(option) {
|
|
||||||
option.disabled = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const selectField = document.getElementById('{{ field_id }}');
|
|
||||||
const placeholder = selectField.getAttribute('data-placeholder') || '';
|
|
||||||
|
|
||||||
const choicesInstance = new Choices(selectField, {
|
|
||||||
removeItemButton: false,
|
|
||||||
placeholderValue: placeholder,
|
|
||||||
searchEnabled: true,
|
|
||||||
shouldSort: false,
|
|
||||||
allowHTML: true,
|
|
||||||
closeDropdownOnSelect: true,
|
|
||||||
removeItemButton: true,
|
|
||||||
searchFields: ['label'],
|
|
||||||
resetScrollPosition: false,
|
|
||||||
callbackOnCreateTemplates: function(template) {
|
|
||||||
const getCardContent = (data) => {
|
|
||||||
let htmlContent = (data.element && data.element.getAttribute('data-html-content')) || data.label;
|
|
||||||
let quantity = data.element.getAttribute('data-quantity');
|
|
||||||
quantity = quantity ? parseInt(quantity) : 1;
|
|
||||||
htmlContent = htmlContent.replace('__QUANTITY__', quantity);
|
|
||||||
return htmlContent;
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderCard = (classNames, data, type) => {
|
|
||||||
const rarity = data.element ? data.element.getAttribute('data-rarity') : '';
|
|
||||||
const cardId = data.element ? data.element.getAttribute('data-card-id') : 0;
|
|
||||||
const cardname = data.element ? data.element.getAttribute('data-name') : '';
|
|
||||||
const content = getCardContent(data);
|
|
||||||
if (type === 'item') {
|
|
||||||
return template(`
|
|
||||||
<div class="${classNames.item} mx-auto w-max ${data.highlighted ? classNames.highlightedState : ''} relative"
|
|
||||||
data-id="${data.id}"
|
|
||||||
data-card-id="${cardId}"
|
|
||||||
data-item
|
|
||||||
data-rarity="${rarity}"
|
|
||||||
data-name="${cardname}"
|
|
||||||
aria-selected="true"
|
|
||||||
style="cursor: pointer; padding: 1rem;">
|
|
||||||
<button type="button" class="decrement absolute left-[-1.5rem] top-1/2 transform -translate-y-1/2 bg-base-300 text-base-content px-2">-</button>
|
|
||||||
<button type="button" class="increment absolute right-[-1.5rem] top-1/2 transform -translate-y-1/2 bg-base-300 text-base-content px-2">+</button>
|
|
||||||
<div class="card-content">${content}</div>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
} else {
|
|
||||||
const extraAttributes = `data-select-text="${this.config.itemSelectText}" data-choice ${
|
|
||||||
data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'
|
|
||||||
}`;
|
|
||||||
const extraClasses = classNames.itemChoice;
|
|
||||||
return template(`
|
|
||||||
<div class="${classNames.item} ${extraClasses} ${data.highlighted ? classNames.highlightedState : ''} mx-auto w-max"
|
|
||||||
${extraAttributes}
|
|
||||||
data-id="${data.id}"
|
|
||||||
data-card-id="${cardId}"
|
|
||||||
data-name="${cardname}"
|
|
||||||
data-choice
|
|
||||||
data-rarity="${rarity}"
|
|
||||||
style="cursor: pointer;">
|
|
||||||
${content}
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
choice: function(classNames, data) {
|
|
||||||
return renderCard(classNames, data, 'choice');
|
|
||||||
},
|
|
||||||
item: function(classNames, data) {
|
|
||||||
return renderCard(classNames, data, 'item');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Associate the Choices instance with the select field.
|
|
||||||
selectField.choicesInstance = choicesInstance;
|
|
||||||
|
|
||||||
if (!window.cardMultiselectInstances) {
|
|
||||||
window.cardMultiselectInstances = [];
|
|
||||||
}
|
|
||||||
window.cardMultiselectInstances.push(selectField);
|
|
||||||
|
|
||||||
selectField.addEventListener('change', function() {
|
|
||||||
if (window.updateGlobalCardFilters) {
|
|
||||||
window.updateGlobalCardFilters();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen for increment/decrement clicks (scoped to the choices container).
|
|
||||||
const choicesContainer = selectField.closest('.choices') || document;
|
|
||||||
|
|
||||||
choicesContainer.addEventListener('click', function(e) {
|
|
||||||
if (e.target.classList.contains('increment')) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
const container = e.target.closest('[data-item]');
|
|
||||||
if (container) {
|
|
||||||
let quantityBadge = container.querySelector('.card-quantity-badge');
|
|
||||||
let quantity = getOptionQuantity(container);
|
|
||||||
quantity = quantity + 1;
|
|
||||||
quantityBadge.innerText = quantity;
|
|
||||||
updateOptionQuantity(container, quantity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.target.classList.contains('decrement')) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
const container = e.target.closest('[data-item]');
|
|
||||||
if (container) {
|
|
||||||
let quantityBadge = container.querySelector('.card-quantity-badge');
|
|
||||||
let quantity = getOptionQuantity(container);
|
|
||||||
const cardId = container.getAttribute('data-card-id');
|
|
||||||
if (quantity === 1) {
|
|
||||||
const option = selectField.querySelector('option[value="' + cardId + '"]');
|
|
||||||
if (option) {
|
|
||||||
choicesInstance.removeActiveItemsByValue(option.value);
|
|
||||||
option.selected = false;
|
|
||||||
}
|
|
||||||
if (window.updateGlobalCardFilters) {
|
|
||||||
window.updateGlobalCardFilters();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quantity = quantity - 1;
|
|
||||||
quantityBadge.innerText = quantity;
|
|
||||||
updateOptionQuantity(container, quantity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.target.closest('[data-item]') &&
|
|
||||||
!e.target.classList.contains('increment') &&
|
|
||||||
!e.target.classList.contains('decrement')) {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateOptionQuantity(item, quantity) {
|
|
||||||
const cardId = item.getAttribute('data-card-id');
|
|
||||||
const option = item.closest('.choices__inner').querySelector('option[value="' + cardId + '"]');
|
|
||||||
if (option) {
|
|
||||||
option.setAttribute('data-quantity', quantity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOptionQuantity(item) {
|
|
||||||
const cardId = item.getAttribute('data-card-id');
|
|
||||||
const option = item.closest('.choices__inner').querySelector('option[value="' + cardId + '"]');
|
|
||||||
return option ? parseInt(option.getAttribute('data-quantity')) : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (choicesInstance.getValue(true).length > 0 && window.updateGlobalCardFilters) {
|
|
||||||
window.updateGlobalCardFilters();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.choices.select {
|
|
||||||
height: inherit;
|
|
||||||
padding-inline-start: 0;
|
|
||||||
}
|
|
||||||
.choices__inner {
|
|
||||||
border: 1px solid var(--color-gray-500) !important;
|
|
||||||
}
|
|
||||||
.choices__list {
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
.choices__list--dropdown {
|
|
||||||
border-left: 1px solid var(--color-gray-500) !important;
|
|
||||||
border-right: 1px solid var(--color-gray-500) !important;
|
|
||||||
border-bottom: 1px solid var(--color-gray-500) !important;
|
|
||||||
border-top: none !important;
|
|
||||||
}
|
|
||||||
.choices.select[data-type*="select-one"]::after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.choices__inner.bg-secondary {
|
|
||||||
background-color: var(--color-secondary);
|
|
||||||
border: none;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
.choices__item.mx-auto.w-max:hover {
|
|
||||||
background-color: #e2e8f0;
|
|
||||||
}
|
|
||||||
.choices__input,
|
|
||||||
.choices__input--cloned {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
.choices__list--dropdown span.card-quantity-badge {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue