When a Task element’s corresponding <button>
element is clicked, open
the Bulk Action <form>
element, nested within the page’s <dialog>
element .
Annotate the <button>
elements with a [data-bulk-value]
attribute,
so that the Bulk.select
action can infer the first
<input type="checkbox">
element within its <form>
to both set
checked = true
and call [.focus()
on][mdn-focus].
Rely on the Tethered
Stimulus controller to absolutely position the
<dialog>
element’s descendant <input type="checkbox">
elements
overlaid on top of their associated
<button data-action~="click->bulk#select">
elements.
Collapse app/javascript/controllers/bulk_controller.js
Expand app/javascript/controllers/bulk_controller.js
app/javascript/controllers/bulk_controller.js
diff --git a/app/javascript/controllers/bulk_controller.js b/app/javascript/controllers/bulk_controller.js
new file mode 100644
index 0000000..d800b82
--- /dev/null
+++ b/app/javascript/controllers/bulk_controller.js
@@ -0,0 +1,21 @@
+import { Controller } from "stimulus"
+
+export default class extends Controller {
+ static targets = [ "form" ]
+
+ select({ currentTarget }) {
+ const value = currentTarget.getAttribute(`data-${this.identifier}-value`)
+ const inputTargets = Array.from(this.formTarget.elements)
+
+ const input = inputTargets.find(input => input.value === value)
+
+ if (input) {
+ input.checked = true
+ input.focus()
+ }
+ }
+
+ resetForm() {
+ this.formTarget.reset()
+ }
+}
Collapse app/javascript/controllers/tethered_controller.js
Expand app/javascript/controllers/tethered_controller.js
app/javascript/controllers/tethered_controller.js
diff --git a/app/javascript/controllers/tethered_controller.js b/app/javascript/controllers/tethered_controller.js
new file mode 100644
index 0000000..4f5f28b
--- /dev/null
+++ b/app/javascript/controllers/tethered_controller.js
@@ -0,0 +1,17 @@
+import { Controller } from "stimulus"
+
+export default class extends Controller {
+ static values = { selector: String }
+
+ connect() {
+ const destinationTarget = document.querySelector(this.selectorValue)
+
+ if (destinationTarget) {
+ const { top, left, height } = destinationTarget.getBoundingClientRect()
+
+ this.element.style.left = left + "px"
+ this.element.style.height = height + "px"
+ this.element.style.top = top + "px"
+ }
+ }
+}
Collapse app/javascript/packs/application.css
Expand app/javascript/packs/application.css
app/javascript/packs/application.css
diff --git a/app/javascript/packs/application.css b/app/javascript/packs/application.css
index 76fcadc..d31f205 100644
--- a/app/javascript/packs/application.css
+++ b/app/javascript/packs/application.css
@@ -1,3 +1,11 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
+
+[open].backdrop\:hidden + .backdrop {
+ display: none;
+}
+
+[open].backdrop\:hidden::backdrop {
+ display: none;
+}
Collapse app/views/events/new.html.erb
Expand app/views/events/new.html.erb
app/views/events/new.html.erb
diff --git a/app/views/events/new.html.erb b/app/views/events/new.html.erb
index f652c8a..3314c46 100644
--- a/app/views/events/new.html.erb
+++ b/app/views/events/new.html.erb
@@ -1,16 +1,28 @@
-<%= form_with(scope: :event, url: completions_path) do |form| %>
+<%= form_with scope: :event, url: completions_path, html: {
+ autocomplete: :off, "data-bulk-target": "form"
+} do |form| %>
<fieldset>
<table>
<tbody>
<%= form.collection_check_boxes :task_ids, tasks.todo, :id, :name do |builder| %>
- <%= render "row" do %>
- <td><%= builder.check_box %></td>
+ <%= render "row", class: "absolute", "data-controller": "tethered",
+ "data-tethered-selector-value": "#" + dom_id(builder.object) do %>
+ <td>
+ <%= builder.check_box class: "
+ focus:shadow-outline
+ form-checkbox
+ h-6
+ hover:shadow-outline
+ text-yellow-500
+ w-6
+ " %>
+ </td>
<td><%= builder.label %></td>
<% end %>
<% end %>
</tbody>
<tfoot>
- <%= render "row" do %>
+ <%= render "row", class: "absolute justify-center left-0 right-0" do %>
<% with_options scope: [:helpers, :submit, :event] do |action| %>
<td>
<%= render "button", builder: form, class: "bg-green-400 text-white" do %>
Collapse app/views/layouts/application.html.erb
Expand app/views/layouts/application.html.erb
app/views/layouts/application.html.erb
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 637c481..364caac 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -9,12 +9,19 @@
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
- <body data-controller="controls-dialog">
+ <body data-controller="bulk controls-dialog">
<main>
<%= yield %>
</main>
- <dialog data-controller="dialog" data-controls-dialog-target="dialog">
+ <dialog data-controller="dialog" data-controls-dialog-target="dialog" data-action="close->bulk#resetForm" class="
+ backdrop:hidden
+ bg-transparent
+ border-0
+ h-full
+ p-0
+ w-full
+ ">
<%= render(template: "events/new", locals: {tasks: Task.all}) %>
</dialog>
</body>
Collapse app/views/tasks/index.html.erb
Expand app/views/tasks/index.html.erb
app/views/tasks/index.html.erb
diff --git a/app/views/tasks/index.html.erb b/app/views/tasks/index.html.erb
index a1f4373..61b2067 100644
--- a/app/views/tasks/index.html.erb
+++ b/app/views/tasks/index.html.erb
@@ -4,10 +4,11 @@
<table>
<% tasks.todo.each do |task| %>
- <%= render "row" do %>
+ <%= render "row", id: dom_id(task) do %>
<td>
<%= render "button", id: dom_id(task, :select), type: :button, class: "form-checkbox h-6 w-6",
- "data-action": "click->controls-dialog#showModal" do %>
+ "data-action": "click->bulk#select click->controls-dialog#showModal",
+ "data-bulk-value": task.id do %>
<span class="sr-only"><%= translate(".select") %></span>
<span class="sr-only" aria-hidden="true"><%= task.name %></span>
<% end %>
Collapse package.json
Expand package.json
package.json
diff --git a/package.json b/package.json
index 5f71393..91c81c8 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
},
"version": "0.1.0",
"devDependencies": {
+ "@tailwindcss/custom-forms": "^0.2.1",
"tailwindcss": "^1.8.7",
"webpack-dev-server": "^3.11.0"
},
Collapse test/system/tasks_test.rb
Expand test/system/tasks_test.rb
test/system/tasks_test.rb
diff --git a/test/system/tasks_test.rb b/test/system/tasks_test.rb
index 2f4f127..6040244 100644
--- a/test/system/tasks_test.rb
+++ b/test/system/tasks_test.rb
@@ -8,7 +8,6 @@ class TasksTest < ApplicationSystemTestCase
visit root_path
click_on do_the_homework.name
- check do_the_homework.name
check pass_the_test.name
click_on submit(:event, :complete)
@@ -24,7 +23,6 @@ class TasksTest < ApplicationSystemTestCase
visit root_path
click_on do_the_homework.name
- check do_the_homework.name
check pass_the_test.name
click_on submit(:event, :delay)