Skip to content

Commit

Permalink
Merge pull request #4715 from pulibrary/4675-copy-seleced-combobox
Browse files Browse the repository at this point in the history
Copy seleced items instead of moving to the top
  • Loading branch information
christinach authored Jan 23, 2025
2 parents 31a860f + 298df83 commit 35d57e8
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 36 deletions.
6 changes: 6 additions & 0 deletions app/assets/stylesheets/components/search--advanced.scss
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@
white-space: normal;
}

.dropdown-item.divider {
pointer-events: none;
border-bottom: 1px solid black;
margin-bottom: 4px;
}

.row .range_limit input.range_begin,
.row .range_limit input.range_end {
width: 5em;
Expand Down
10 changes: 5 additions & 5 deletions app/components/multiselect_combobox_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
aria-expanded="false" aria-controls="<%= @listbox_id %>">
<span class="fa fa-caret-down" aria-hidden="true" data-bs-toggle="dropdown"></span>
<ul class="dropdown-menu" role="listbox" aria-label="Options" id="<%= @listbox_id %>">
<% @values.each do |value| %>
<% if @field_name == 'advanced_location_s' %>
<%= content_tag :li,
value[:label],
'All Princeton Holdings',
class: 'dropdown-item',
tabindex: -1,
role: 'option' %>
<% end %>
<% if @field_name == 'advanced_location_s' %>
<% @values.each do |value| %>
<%= content_tag :li,
'pul',
value[:label],
class: 'dropdown-item',
tabindex: -1,
role: 'option' %>
Expand All @@ -32,7 +32,7 @@
<% end %>
<% if @field_name == 'advanced_location_s' %>
<%= content_tag :option,
'pul',
'All Princeton Holdings',
value: 'pul',
selected: params.dig('f_inclusive', 'advanced_location_s', 0) == 'pul' %>
<% end %>
Expand Down
90 changes: 61 additions & 29 deletions app/javascript/orangelight/multiselect_combobox.es6
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default class MultiselectCombobox {
this.selectedOptions.toggle(item.firstChild.nodeValue);
this.inputElement.value = this.selectedOptions.toString();
this.#updateHiddenSelect();
this.#orderList();
this.#buildList();
}

updateOptionVisibility() {
Expand All @@ -51,7 +51,18 @@ export default class MultiselectCombobox {

#addEventListeners() {
this.listElement.querySelectorAll('li').forEach((item) => {
item.addEventListener('keyup', (event) => {
this.#addEventListener(item);
});
this.inputElement.addEventListener('input', (event) => {
this.updateOptionVisibility();
this.#openDropdownIfClosed();
});
}

#addEventListener(item) {
item.addEventListener(
'keyup',
(event) => {
if (event.code == 'Enter') {
this.toggleItem(item);
} else {
Expand All @@ -61,19 +72,20 @@ export default class MultiselectCombobox {
new KeyboardEvent('keyup', { key: event.key, code: event.code })
);
}
});
item.addEventListener('click', (event) => {
},
this
);
item.addEventListener(
'click',
(event) => {
this.toggleItem(item);
// Don't propagate the event to the bootstrap event
// listener. Otherwise, the dropdown closes every
// time the user clicks on an item
event.stopPropagation();
});
});
this.inputElement.addEventListener('input', (event) => {
this.updateOptionVisibility();
this.#openDropdownIfClosed();
});
},
this
);
}

#applySelections() {
Expand All @@ -91,6 +103,17 @@ export default class MultiselectCombobox {
item.querySelectorAll('span').forEach((span) => span.remove());
item.classList.remove('active');
item.setAttribute('aria-selected', 'false');
const active = this.listElement.querySelectorAll('.active');
for (const element of active) {
if (
element.firstChild.textContent.trim() ===
item.firstChild.textContent.trim()
) {
element.querySelector('span').remove();
element.classList.remove('active');
break;
}
}
} else {
item.innerHTML += icon;
item.classList.add('active');
Expand Down Expand Up @@ -120,27 +143,36 @@ export default class MultiselectCombobox {
}
}

#orderList() {
[].slice
.call(this.listElement.children)
.sort(this.#compare)
.forEach(function (val, i) {
this.listElement.appendChild(val);
}, this);
}
#buildList() {
let selectedList = [];
let allOptions = [];

#compare(a, b) {
function toBoolean(value) {
return value === 'true' ? true : false;
}
[].slice.call(this.listElement.children).forEach(function (val, i) {
if (val.children.length > 0) {
let copy = val.cloneNode(true);
this.#addEventListener(copy);
selectedList.push(copy);
}
allOptions.push(val);
if (val.classList.contains('divider')) {
selectedList = [];
allOptions = [];
}
}, this);

if (
toBoolean(a.getAttribute('aria-selected')) !==
toBoolean(b.getAttribute('aria-selected'))
) {
return toBoolean(a.getAttribute('aria-selected')) ? -1 : 1;
} else {
return a.textContent.localeCompare(b.textContent);
let divider = document.createElement('li');
divider.classList.add('dropdown-item', 'divider');
divider.tabIndex = -1;
divider.role = 'option';

if (selectedList.length > 0) {
selectedList.push(divider);
}

selectedList = selectedList.concat(allOptions);
this.listElement.innerHTML = '';
selectedList.forEach(function (val) {
this.listElement.appendChild(val);
}, this);
}
}
2 changes: 1 addition & 1 deletion spec/features/advanced_searching_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
holding_location = find_field('advanced_location_s')
holding_location.click
drop_down = holding_location.sibling(".dropdown-menu")
expect(drop_down).to have_content("pul")
expect(drop_down).to have_content("All Princeton Holdings")
end

it 'allows searching by publication date', js: true do
Expand Down
10 changes: 9 additions & 1 deletion spec/javascript/orangelight/multiselect_combobox.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@ describe('MultiselectCombobox', () => {
</div>`;
combobox = new MultiselectCombobox(document.querySelector('input'));
});
it('Moves the active option to the top', () => {
it('Copies the active option to the top', () => {
expect(document.querySelectorAll('li')[0].textContent).toEqual('Lewis');
expect(document.querySelectorAll('li')[3].textContent).toEqual('Lewis');
});
it('Adds a checkmark icon to the <li>', () => {
expect(
Expand All @@ -146,5 +147,12 @@ describe('MultiselectCombobox', () => {
it('Adds the text to the <input>', () => {
expect(document.querySelector('input').value).toEqual('Lewis');
});
it('Removes just the copied option', () => {
document.querySelectorAll('li')[0].click();
expect(document.querySelectorAll('li')[0].textContent).toEqual(
'Firestone'
);
expect(document.querySelectorAll('li')[1].textContent).toEqual('Lewis');
});
});
});

0 comments on commit 35d57e8

Please sign in to comment.