diff --git a/app/controllers/elements_controller.rb b/app/controllers/elements_controller.rb index 109b1cd..152c904 100644 --- a/app/controllers/elements_controller.rb +++ b/app/controllers/elements_controller.rb @@ -49,7 +49,12 @@ class ElementsController < ApplicationController # PATCH/PUT /elements/1 def update if @element.update(element_params) - redirect_to @element, notice: "Element was successfully updated.", status: :see_other + respond_to do |format| + format.turbo_stream + format.html do + redirect_to @element, notice: "Element was successfully updated.", status: :see_other + end + end else render :edit, status: :unprocessable_entity end @@ -82,6 +87,6 @@ class ElementsController < ApplicationController # Only allow a list of trusted parameters through. def element_params - params.require(:element).permit(:page_id, :title, :description) + params.require(:element).permit(:page_id, :title, :description, :position) end end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 2352858..13f2fb8 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -35,7 +35,12 @@ class PagesController < ApplicationController # PATCH/PUT /pages/1 def update if @page.update(page_params) - redirect_to @page, notice: "Page was successfully updated.", status: :see_other + respond_to do |format| + format.turbo_stream + format.html do + redirect_to @page, notice: "Page was successfully updated.", status: :see_other + end + end else render :edit, status: :unprocessable_entity end diff --git a/app/controllers/success_criteria_controller.rb b/app/controllers/success_criteria_controller.rb index d22c7b9..4ae7840 100644 --- a/app/controllers/success_criteria_controller.rb +++ b/app/controllers/success_criteria_controller.rb @@ -115,7 +115,7 @@ class SuccessCriteriaController < ApplicationController # Only allow a list of trusted parameters through. def success_criterion_params - params.require(:success_criterion).permit(:element_id, :title, :quick_criterion, :quick_fail, :quick_fix, :priority, :level, :result, :test_comment, :check_id) + params.require(:success_criterion).permit(:element_id, :title, :quick_criterion, :quick_fail, :quick_fix, :priority, :level, :result, :test_comment, :check_id, :position) end def set_element diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 1274033..6803226 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -34,6 +34,12 @@ application.register("rich-text-link-targets", RichTextLinkTargetsController) import SetThemeController from "./set_theme_controller" application.register("set-theme", SetThemeController) +import SortElementsController from "./sort_elements_controller" +application.register("sort-elements", SortElementsController) + +import SortableController from "./sortable_controller" +application.register("sortable", SortableController) + import ThemeSwitcherController from "./theme_switcher_controller" application.register("theme-switcher", ThemeSwitcherController) diff --git a/app/javascript/controllers/sort_elements_controller.js b/app/javascript/controllers/sort_elements_controller.js new file mode 100644 index 0000000..4a0fb43 --- /dev/null +++ b/app/javascript/controllers/sort_elements_controller.js @@ -0,0 +1,7 @@ +import { Controller } from "@hotwired/stimulus" + +// Connects to data-controller="sort-elements" +export default class extends Controller { + connect() { + } +} diff --git a/app/javascript/controllers/sortable_controller.js b/app/javascript/controllers/sortable_controller.js new file mode 100644 index 0000000..a5b9ca3 --- /dev/null +++ b/app/javascript/controllers/sortable_controller.js @@ -0,0 +1,55 @@ +import { Controller } from "@hotwired/stimulus" +import Sortable from "sortablejs" +import { put } from "@rails/request.js"; + +// Connects to data-controller="sortable" +export default class extends Controller { + linkedElement = null + connect() { + this.element.style.cursor = "grab" + + console.log("dataset", this.element.dataset) + if (this.element.dataset["linkedElementId"]) { + this.linkedElement = document.getElementById(this.element.dataset["linkedElementId"]) + console.log("Has a linked element", this.linkedElement) + } + + new Sortable(this.element, { + group: this.groupValue, + onEnd: this.onEndFactory(this.linkedElement), + }) + } + + onEndFactory(linkedElement) { + return function (event) { + const position = event.newIndex + 1 + const url = event.item.dataset["sortableUrl"] + const formName = event.item.dataset["formName"] + const positionAttribute = event.item.dataset["positionAttribute"] + let body = {} + body[formName] = {} + body[formName][positionAttribute] = position + console.log("event", event, "url", url) + // Expect backend to update list items via turbo if necessary + put(url, { + body: JSON.stringify(body), + contentType: "application/json", + headers: { + "Accept": "text/vnd.turbo-stream.html, text/html, application/xhtml+xml" + } + }) + console.log(linkedElement) + if (linkedElement) { + console.log("move linked", linkedElement) + let children = linkedElement.children + let child = children[event.oldIndex] + let newAfter = children[event.newIndex] + if (event.oldIndex < event.newIndex) { + newAfter = children[event.newIndex + 1] + } + console.log("move ", child, "before", newAfter) + child.parentNode.insertBefore(child, newAfter) + } + } + } +} diff --git a/app/models/checklist_entry.rb b/app/models/checklist_entry.rb index 2cfe0c6..1d74b64 100644 --- a/app/models/checklist_entry.rb +++ b/app/models/checklist_entry.rb @@ -7,6 +7,7 @@ class ChecklistEntry < ApplicationRecord before_validation :set_position before_update :update_positions, if: :position_changed? + private def set_position self.position ||= (checklist.checklist_entries.pluck(:position).max || 0) + 1 end diff --git a/app/models/element.rb b/app/models/element.rb index 5d86afe..11f4b49 100644 --- a/app/models/element.rb +++ b/app/models/element.rb @@ -8,7 +8,8 @@ class Element < ApplicationRecord delegate :report, to: :page - after_validation :set_position + before_validation :set_position + before_update :update_positions, if: :position_changed? # Calculate actual conformity level: # - if a success_criterion has result :failed -> the confirmity_level @@ -33,12 +34,20 @@ class Element < ApplicationRecord @max_level ||= success_criteria.reject(&:not_applicable?).max(&:level) end + def number + "#{page.position}.#{position}" + end + + private def set_position Rails.logger.debug("element: position #{position}") self.position ||= (page.elements.pluck(:position).max || 0) + 1 end - def number - "#{page.position}.#{position}" + def update_positions + if position_was + page.elements.where("position > ?", position_was).update_all("position = position - 1") + end + page.elements.where(position: position..).update_all("position = position + 1") end end diff --git a/app/models/page.rb b/app/models/page.rb index e19ab6f..29bb751 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -1,13 +1,22 @@ class Page < ApplicationRecord belongs_to :report, touch: true - has_many :elements, dependent: :destroy + has_many :elements, -> { order(:position) }, dependent: :destroy has_rich_text :comment before_validation :set_position + before_update :update_positions, if: :position_changed? + private def set_position self.position ||= (report.pages.pluck(:position).max || 0) + 1 end + + def update_positions + if position_was + report.pages.where("position > ?", position_was).update_all("position = position - 1") + end + report.pages.where(position: position..).update_all("position = position + 1") + end end diff --git a/app/models/report.rb b/app/models/report.rb index 9acc234..cb36945 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Report < ApplicationRecord - has_many :pages, dependent: :destroy + has_many :pages, -> { order(:position) }, dependent: :destroy has_many :elements, through: :pages, dependent: :destroy has_rich_text :comment diff --git a/app/models/success_criterion.rb b/app/models/success_criterion.rb index 218bb49..03c97fa 100644 --- a/app/models/success_criterion.rb +++ b/app/models/success_criterion.rb @@ -15,6 +15,7 @@ class SuccessCriterion < ApplicationRecord enum :level, %i[A AA AAA] before_save :set_position + before_update :update_positions, if: :position_changed? def level_value return nil unless level @@ -26,9 +27,20 @@ class SuccessCriterion < ApplicationRecord "HEADER" end + def number + [ page.position, element.position, position ].join(".") + end + private def set_position self.position ||= (element.success_criteria.pluck(:position).max || 0) + 1 Rails.logger.debug("set position: "+position.to_s) end + + def update_positions + if position_was + element.success_criteria.where("position > ?", position_was).update_all("position = position - 1") + end + element.success_criteria.where(position: position..).update_all("position = position + 1") + end end diff --git a/app/views/elements/_element.html.erb b/app/views/elements/_element.html.erb index 83902bc..7cd7df2 100644 --- a/app/views/elements/_element.html.erb +++ b/app/views/elements/_element.html.erb @@ -26,7 +26,7 @@
<% end %> -