Skip to content

Commit

Permalink
Refactor ingredient groups into details/summary
Browse files Browse the repository at this point in the history
These native components let us remove all the custom
event handling and state management from the element editor.
  • Loading branch information
tvdeyen committed Nov 30, 2023
1 parent 48bc1c2 commit af2d60c
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 80 deletions.
16 changes: 6 additions & 10 deletions app/assets/stylesheets/alchemy/elements.scss
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ alchemy-tinymce {
padding-bottom: 0;
}

.ingredient-group-header {
summary {
display: flex;
align-items: center;
justify-content: space-between;
Expand All @@ -468,18 +468,14 @@ alchemy-tinymce {
padding: $default-padding 1px;
}

.ingredient-group-ingredients {
display: none;
}

&.expanded {
.ingredient-group-ingredients {
display: block;
}

&[open] {
.ingredient-group-expand {
@extend .fa-angle-up;
}

> :not(summary) {
box-sizing: border-box;
}
}
}

Expand Down
41 changes: 19 additions & 22 deletions app/javascript/alchemy_admin/components/element_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,6 @@ export class ElementEditor extends HTMLElement {
this.toggle()
}
})
on(
"click",
this.bodySelector,
"[data-toggle-ingredient-group]",
function (event) {
self.onToggleIngredientGroup(this)
event.preventDefault()
}
)

if (this.hasChildren) {
this.addEventListener("alchemy:element-update-title", (event) => {
Expand All @@ -69,6 +60,14 @@ export class ElementEditor extends HTMLElement {
}

if (this.body) {
this.body
.querySelectorAll(".ingredient-group")
.forEach((ingredientGroup) => {
ingredientGroup.addEventListener("toggle", () => {
this.onToggleIngredientGroup(ingredientGroup)
})
})

// We use of @rails/ujs for Rails remote forms
this.body.addEventListener("ajax:success", (event) => {
const responseJSON = event.detail[0]
Expand Down Expand Up @@ -96,10 +95,11 @@ export class ElementEditor extends HTMLElement {
const expanded_ingredient_groups = localStorage.getItem(
"Alchemy.expanded_ingredient_groups"
)
Array.from(JSON.parse(expanded_ingredient_groups)).forEach((header_id) => {
const header = document.querySelector(`#${header_id}`)
const group = header?.closest(".ingredient-group")
group?.classList.add("expanded")
Array.from(JSON.parse(expanded_ingredient_groups)).forEach((group_id) => {
const group = document.querySelector(`#${group_id}`)
if (group) {
group.open = true
}
})
}

Expand Down Expand Up @@ -174,24 +174,21 @@ export class ElementEditor extends HTMLElement {

/**
* Toggle visibility of the ingredient fields in the group
* @param {HTMLLinkElement} target
* @param {HTMLLinkElement} group
*/
onToggleIngredientGroup(target) {
const group_div = target.closest(".ingredient-group")
group_div.classList.toggle("expanded")

onToggleIngredientGroup(group) {
let expanded_ingredient_groups = JSON.parse(
localStorage.getItem("Alchemy.expanded_ingredient_groups") || "[]"
)

// Add or remove depending on whether this ingredient group is expanded
if (group_div.classList.contains("expanded")) {
if (expanded_ingredient_groups.indexOf(target.id) === -1) {
expanded_ingredient_groups.push(target.id)
if (group.open) {
if (expanded_ingredient_groups.indexOf(group.id) === -1) {
expanded_ingredient_groups.push(group.id)
}
} else {
expanded_ingredient_groups = expanded_ingredient_groups.filter(
(value) => value !== target.id
(value) => value !== group.id
)
}

Expand Down
12 changes: 5 additions & 7 deletions app/views/alchemy/admin/elements/_element.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,13 @@

<!-- Each ingredient group -->
<% element.ingredients.select { |i| i.definition[:group] }.group_by { |i| i.definition[:group] }.each do |group, ingredients| %>
<div class="ingredient-group">
<%= link_to '#', id: "element_#{element.id}_ingredient_group_#{group.parameterize.underscore}_header", class: 'ingredient-group-header', data: { toggle_ingredient_group: true } do %>
<%= content_tag :details, class: "ingredient-group", id: "element_#{element.id}_ingredient_group_#{group.parameterize.underscore}" do %>
<summary>
<%= element.translated_group group %>
<i class="ingredient-group-expand icon fa-fw fa-angle-down fas"></i>
<% end %>
<%= content_tag :div, id: "element_#{element.id}_ingredient_group_#{group.parameterize.underscore}", class: 'ingredient-group-ingredients' do %>
<%= render ingredients, element_form: f %>
<% end %>
</div>
</summary>
<%= render ingredients, element_form: f %>
<% end %>
<% end %>
</div>
<% end %>
Expand Down
31 changes: 1 addition & 30 deletions spec/features/admin/edit_elements_feature_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -147,38 +147,9 @@
# Need to be on page editor rather than just admin_elements in order to have JS interaction
before { visit alchemy.edit_admin_page_path(element.page) }

scenario "collapsed ingredient groups shown", :js do
# No group ingredient initially visible
expect(page).not_to have_selector(".ingredient-group-ingredients", visible: true)

page.find("a#element_#{element.id}_ingredient_group_details_header", text: "Details").click
# 'Details' group ingredient visible
expect(page).to have_selector("#element_#{element.id}_ingredient_group_details", visible: true)
within("#element_#{element.id}_ingredient_group_details") do
expect(page).to have_selector("[data-ingredient-role='description']")
expect(page).to have_selector("[data-ingredient-role='key_words']")
end
expect(page).to have_selector("#element_#{element.id}_ingredient_group_details", visible: true)

# 'Size' group ingredient not visible
expect(page).not_to have_selector("#element_#{element.id}_ingredient_group_size", visible: true)

page.find("a#element_#{element.id}_ingredient_group_size_header", text: "Size").click
# 'Size' group now visible
expect(page).to have_selector("#element_#{element.id}_ingredient_group_size", visible: true)
within("#element_#{element.id}_ingredient_group_size") do
expect(page).to have_selector("[data-ingredient-role='width']")
expect(page).to have_selector("[data-ingredient-role='height']")
end

page.find("a#element_#{element.id}_ingredient_group_size_header", text: "Size").click
# 'Size' group hidden
expect(page).not_to have_selector("#element_#{element.id}_ingredient_group_size", visible: true)
end

scenario "expanded ingredient groups persist between visits", :js do
expect(page).not_to have_selector("#element_#{element.id}_ingredient_group_details", visible: true)
page.find("a#element_#{element.id}_ingredient_group_details_header", text: "Details").click
page.find("details#element_#{element.id}_ingredient_group_details", text: "Details").click
expect(page).to have_selector("#element_#{element.id}_ingredient_group_details", visible: true)
visit alchemy.edit_admin_page_path(element.page)
expect(page).to have_selector("#element_#{element.id}_ingredient_group_details", visible: true)
Expand Down
24 changes: 13 additions & 11 deletions spec/javascript/alchemy_admin/components/element_editor.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,24 +212,26 @@ describe("alchemy-element-editor", () => {
})

describe("on click on ingredient group header", () => {
it("expands ingredient group", () => {
it("stores ingredient group state in localStorage", () => {
editor = getComponent(`
<alchemy-element-editor id="element_123">
<form class="element-body">
<div class="ingredient-group">
<a class="ingredient-group-header" data-toggle-ingredient-group="">
Details
</a>
<details class="ingredient-group">
<summary>Details</summary>
<div class="ingredient-group-ingredients"></div>
</div>
</details>
</form>
</alchemy-element-editor>
`)
const header = editor.querySelector(".ingredient-group-header")
const click = new Event("click", { bubbles: true })
header.dispatchEvent(click)
const group = editor.querySelector(".ingredient-group")
expect(group.classList.contains("expanded")).toBeTruthy()
const group = editor.querySelector("details")
expect(
localStorage.hasOwnProperty("Alchemy.expanded_ingredient_groups")
).toBeFalsy()
const click = new Event("toggle", { bubbles: true })
group.dispatchEvent(click)
expect(
localStorage.hasOwnProperty("Alchemy.expanded_ingredient_groups")
).toBeTruthy()
localStorage.clear()
})
})
Expand Down

0 comments on commit af2d60c

Please sign in to comment.