Multi selection combos working
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
import { toSentence } from "helpers/text_helpers"
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
#hiddenField
|
||||||
|
|
||||||
|
static targets = [ "label", "item", "hiddenFieldTemplate" ]
|
||||||
|
static values = {
|
||||||
|
selectPropertyName: { type: String, default: "aria-checked" },
|
||||||
|
defaultValue: String,
|
||||||
|
noSelectionLabel: { type: String, default: "No selection" }
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.labelTarget.textContent = this.#selectedLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
change(event) {
|
||||||
|
const item = event.target.closest("[role='checkbox']")
|
||||||
|
if (item) {
|
||||||
|
this.#toggleSelection(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get #selectedLabel() {
|
||||||
|
const selectedValues = this.#selectedValues()
|
||||||
|
if (selectedValues.length === 0) {
|
||||||
|
return this.noSelectionLabelValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const labels = this.#selectedItems().map(item => item.dataset.multiSelectionComboboxLabel)
|
||||||
|
return toSentence(labels, {
|
||||||
|
two_words_connector: " or ",
|
||||||
|
last_word_connector: ", or "
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#toggleSelection(item) {
|
||||||
|
const isSelected = item.getAttribute(this.selectPropertyNameValue) === "true"
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
item.setAttribute(this.selectPropertyNameValue, "false")
|
||||||
|
} else {
|
||||||
|
item.setAttribute(this.selectPropertyNameValue, "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#updateHiddenFields()
|
||||||
|
this.labelTarget.textContent = this.#selectedLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
#updateHiddenFields() {
|
||||||
|
this.#clearHiddenFields()
|
||||||
|
this.#addHiddenFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
#selectedItems() {
|
||||||
|
return this.itemTargets.filter(item =>
|
||||||
|
item.getAttribute(this.selectPropertyNameValue) === "true"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#selectedValues() {
|
||||||
|
return this.#selectedItems().map(item => item.dataset.multiSelectionComboboxValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
#clearHiddenFields() {
|
||||||
|
this.element.querySelectorAll('input[type="hidden"]').forEach(field => {
|
||||||
|
if (field !== this.hiddenField) {
|
||||||
|
field.remove()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#addHiddenFields() {
|
||||||
|
this.#selectedValues().forEach(value => {
|
||||||
|
const [field] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
|
||||||
|
field.value = value
|
||||||
|
this.element.appendChild(field)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,3 +11,27 @@ export function normalizeFilteredText(string) {
|
|||||||
export function filterMatches(text, potentialMatch) {
|
export function filterMatches(text, potentialMatch) {
|
||||||
return normalizeFilteredText(text).includes(normalizeFilteredText(potentialMatch))
|
return normalizeFilteredText(text).includes(normalizeFilteredText(potentialMatch))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toSentence(array, options = {}) {
|
||||||
|
const defaultConnectors = {
|
||||||
|
words_connector: ", ",
|
||||||
|
two_words_connector: " and ",
|
||||||
|
last_word_connector: ", and "
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectors = { ...defaultConnectors, ...options }
|
||||||
|
|
||||||
|
if (array.length === 0) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array.length === 1) {
|
||||||
|
return array[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array.length === 2) {
|
||||||
|
return array.join(connectors.two_words_connector)
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.slice(0, -1).join(connectors.words_connector) + connectors.last_word_connector + array[array.length - 1]
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
||||||
<%= render "filters/settings/sorted_by", user_filtering: user_filtering %>
|
<%= render "filters/settings/sorted_by", user_filtering: user_filtering %>
|
||||||
<%= render "filters/settings/indexed_by", user_filtering: user_filtering %>
|
<%= render "filters/settings/indexed_by", user_filtering: user_filtering %>
|
||||||
<%#= render "filters/settings/tags", user_filtering: user_filtering %>
|
<%= render "filters/settings/tags", user_filtering: user_filtering %>
|
||||||
<%#= render "filters/settings/assignees", user_filtering: user_filtering %>
|
<%#= render "filters/settings/assignees", user_filtering: user_filtering %>
|
||||||
<%#= render "filters/settings/creators", user_filtering: user_filtering %>
|
<%#= render "filters/settings/creators", user_filtering: user_filtering %>
|
||||||
<%#= render "filters/settings/closers", user_filtering: user_filtering %>
|
<%#= render "filters/settings/closers", user_filtering: user_filtering %>
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
<% filter = user_filtering.filter %>
|
<% filter = user_filtering.filter %>
|
||||||
|
|
||||||
<%= tag.div class: "quick-filter position-relative",
|
<%= tag.div class: "quick-filter position-relative",
|
||||||
data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_tags? } do %>
|
data: {
|
||||||
<button class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#open:stop">
|
controller: "dialog multi-selection-combobox",
|
||||||
<span class="overflow-ellipsis">
|
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside",
|
||||||
<% if filter.tags.any? %>
|
filter_show: user_filtering.show_tags?,
|
||||||
<%= filter.tags.map(&:hashtag).to_sentence(two_words_connector: " or ", last_word_connector: ", or ") %>
|
multi_selection_combobox_no_selection_label_value: "Tagged…" } do %>
|
||||||
<% else %>
|
<button type="button" class="btn input input--select flex-inline txt-x-small" data-action="click->dialog#toggle:stop">
|
||||||
Tagged…
|
<span class="overflow-ellipsis" data-multi-selection-combobox-target="label">
|
||||||
<% end %>
|
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<template data-multi-selection-combobox-target="hiddenFieldTemplate">
|
||||||
|
<%= hidden_field_tag "tag_ids[]", nil, data: { filter_settings_target: "field" } %>
|
||||||
|
</template>
|
||||||
|
|
||||||
<%= filter_dialog "Tagged…" do %>
|
<%= filter_dialog "Tagged…" do %>
|
||||||
<strong class="popup__title">Tagged…</strong>
|
<strong class="popup__title">Tagged…</strong>
|
||||||
|
|
||||||
@@ -20,34 +23,16 @@
|
|||||||
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
type: "search", autocorrect: "off", autocomplete: "off", data: { "1p-ignore": "true", filter_target: "input", action: "input->filter#filter" } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<ul class="popup__list" data-filter-target="list">
|
<ul class="popup__list" data-filter-target="list" role="listbox">
|
||||||
<% user_filtering.tags.each do |tag| %>
|
<% user_filtering.tags.each do |tag| %>
|
||||||
<li class="popup__item" data-filter-target="item" data-navigable-list-target="item">
|
<%= content_tag(:li, class: "popup__item", data: {
|
||||||
<%= form_with url: cards_path, method: :get, class: "full-width", data: { controller: "form" } do |form| %>
|
navigable_list_target: "item", multi_selection_combobox_target: "item", multi_selection_combobox_value: tag.id, multi_selection_combobox_label: tag.hashtag },
|
||||||
<% filter.as_params.except(:tag_ids).each do |key, value| %>
|
role: "checkbox", aria: { checked: filter.tags.include?(tag) }) do %>
|
||||||
<%= filter_hidden_field_tag key, value %>
|
<button type="button" class="btn popup__btn" data-action="dialog#close multi-selection-combobox#change form#submit filter-settings#change">
|
||||||
<% end %>
|
<span class="overflow-ellipsis flex-item-grow"><%= tag.hashtag %></span>
|
||||||
|
<%= icon_tag "check", class: "checked flex-item-justify-end", "aria-hidden": true %>
|
||||||
<% filter.tags.each do |existing_tag| %>
|
</button>
|
||||||
<% unless existing_tag == tag %>
|
<% end %>
|
||||||
<%= hidden_field_tag "tag_ids[]", existing_tag.id %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% unless filter.tags.include?(tag) %>
|
|
||||||
<%= hidden_field_tag "tag_ids[]", tag.id %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %>
|
|
||||||
|
|
||||||
<%= form.button type: "submit", class: "popup__btn btn" do %>
|
|
||||||
<span class="overflow-ellipsis flex-item-grow"><%= tag.hashtag %></span>
|
|
||||||
<% if filter.tags.include?(tag) %>
|
|
||||||
<%= icon_tag "check", class: "checked flex-item-justify-end" %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
</li>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
Reference in New Issue
Block a user