Skip to content

Commit

Permalink
Fix picture selector behavior (#2964)
Browse files Browse the repository at this point in the history
Fixes a few issues:

1. Checkbox becomes invisible after selecting/unselecting an image
2. Selection toolbar is not visible when one or multiple images are selected

Updates pictures select all behavior:

- when no pictures selected then all pictures selected
- when one/many pictures selected then all pictures selected instead of toggling of picture selection state

Closes #2960
  • Loading branch information
ovinix committed Jul 5, 2024
1 parent 7a5adee commit 7a235c2
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 20 deletions.
48 changes: 38 additions & 10 deletions app/javascript/alchemy_admin/picture_selector.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,62 @@
import { on } from "alchemy_admin/utils/events"

function toggleCheckboxes(state) {
document
.querySelectorAll(".picture_tool.select input[type='checkbox']")
.forEach((checkbox) => {
checkbox.checked = state
checkbox.closest(".picture_thumbnail").classList.toggle("active", state)
})
}

function checkedInputs() {
return document.querySelectorAll("#picture_archive input:checked")
}

function editMultiplePicturesUrl(href) {
const searchParameters = new URLSearchParams()
checkedInputs().forEach((entry) =>
searchParameters.append(entry.name, entry.value)
)
const url = href + "?" + searchParameters.toString()

return url
}

/**
* Multiple picture select handler for the picture archive.
*/
export default function PictureSelector() {
const selectAllButton = document.querySelector("#select_all_pictures")
const selectedItemTools = document.querySelector(".selected_item_tools")
const checkedInputs = () =>
document.querySelectorAll("#picture_archive input:checked")

on("click", ".toolbar_buttons", "a#select_all_pictures", (event) => {
event.preventDefault()

selectAllButton.classList.toggle("active")

const state = selectAllButton.classList.contains("active")

toggleCheckboxes(state)

selectedItemTools.classList.toggle("hidden", !state)
})

// make the item toolbar visible and show the checkbox also if it is not hovered anymore
on("change", ".picture_tool.select", "input", (event) => {
selectedItemTools.style.display =
checkedInputs().length > 0 ? "block" : "none"
selectedItemTools.classList.toggle("hidden", checkedInputs().length === 0)

const parentElementClassList = event.target.parentElement.classList
const checked = event.target.checked

parentElementClassList.toggle("visible", checked)
parentElementClassList.toggle("hidden", !checked)
})

// open the edit view in a dialog modal
on("click", ".selected_item_tools", "a#edit_multiple_pictures", (event) => {
event.preventDefault()

const searchParameters = new URLSearchParams()
checkedInputs().forEach((entry) =>
searchParameters.append(entry.name, entry.value)
)
const url = event.target.href + "?" + searchParameters.toString()
const url = editMultiplePicturesUrl(event.target.href)

Alchemy.openDialog(url, {
title: event.target.title,
Expand Down
10 changes: 0 additions & 10 deletions app/views/alchemy/admin/pictures/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,6 @@
<script type="text/javascript" charset="utf-8">
$(function() {
Alchemy.pictureSelector();
$('#select_all_pictures').on('click', function(e) {
$(this).toggleClass("active")
$('.picture_tool.select :checkbox')
.prop('checked', function(_i, val) { return !val })
.closest(".picture_thumbnail")
.toggleClass("active");
e.preventDefault;
$(".selected_item_tools").toggleClass("hidden")
return false;
});
$('#picture_archive').on("click", ".thumbnail_background", function(event) {
var url = $(this).attr('href');
var overlay = new Alchemy.ImageOverlay(url);
Expand Down
63 changes: 63 additions & 0 deletions spec/javascript/alchemy_admin/picture_selector.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import PictureSelector from "alchemy_admin/picture_selector"

describe("PictureSelector", () => {
beforeEach(() => {
document.body.innerHTML = `
<div class="toolbar_buttons">
<a id="select_all_pictures"></a>
</div>
<div class="selected_item_tools hidden"></div>
<div id="picture_archive">
<div class="picture_thumbnail">
<span class="picture_tool select">
<input type="checkbox" name="picture_ids[]" id="checkbox_1" value="1">
</span>
</div>
<div class="picture_thumbnail">
<span class="picture_tool select">
<input type="checkbox" name="picture_ids[]" id="checkbox_2" value="1">
</span>
</div>
</div>
`

PictureSelector()
})

it("selects/unselects all images and toggles selection toolbar visibility", () => {
const selectAllButton = document.querySelector("#select_all_pictures")
const checkboxOne = document.querySelector("#checkbox_1")
const checkboxTwo = document.querySelector("#checkbox_2")
const selectionToolbar = document.querySelector(".selected_item_tools")

selectAllButton.click()

expect(selectAllButton.classList.contains("active")).toBeTruthy()
expect(selectionToolbar.classList.contains("hidden")).toBeFalsy()
expect(checkboxOne.checked).toBeTruthy()
expect(checkboxTwo.checked).toBeTruthy()

selectAllButton.click()

expect(selectAllButton.classList.contains("active")).toBeFalsy()
expect(selectionToolbar.classList.contains("hidden")).toBeTruthy()
expect(checkboxOne.checked).toBeFalsy()
expect(checkboxTwo.checked).toBeFalsy()
})

it("toggles selection toolbar visibility when one image is selected/unselected", () => {
const selectionToolbar = document.querySelector(".selected_item_tools")
const checkboxParent = document.querySelector(".picture_tool")
const checkbox = document.querySelector("#checkbox_1")

checkbox.click()

expect(selectionToolbar.classList.contains("hidden")).toBeFalsy()
expect(checkboxParent.classList.contains("visible")).toBeTruthy()

checkbox.click()

expect(selectionToolbar.classList.contains("hidden")).toBeTruthy()
expect(checkboxParent.classList.contains("visible")).toBeFalsy()
})
})

0 comments on commit 7a235c2

Please sign in to comment.