Skip to content

Commit faf2298

Browse files
authored
replace action_bar hot keys with Stimulus (#1423)
1 parent fda194e commit faf2298

File tree

8 files changed

+90
-113
lines changed

8 files changed

+90
-113
lines changed

app/javascript/controllers/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ application.register("hotkeys", HotkeysController);
1515
import KeepUnreadToggleController from "./keep_unread_toggle_controller";
1616
application.register("keep-unread-toggle", KeepUnreadToggleController);
1717

18+
import MarkAllAsReadController from "./mark_all_as_read_controller";
19+
application.register("mark-all-as-read", MarkAllAsReadController);
20+
1821
import StarToggleController from "./star_toggle_controller";
1922
application.register("star-toggle", StarToggleController);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {Controller} from "@hotwired/stimulus";
2+
3+
import {assert} from "helpers/assert";
4+
5+
export default class extends Controller {
6+
static override targets = ["form"];
7+
8+
formTarget!: HTMLFormElement;
9+
10+
submit(event: Event): void {
11+
event.preventDefault();
12+
13+
assert(this.formTarget).requestSubmit();
14+
}
15+
}
Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
<div class="row">
1+
<div class="row" data-controller="hotkeys mark-all-as-read" data-action="keydown@document->hotkeys#handleKeydown">
22
<div class="pull-left">
33
<a class="btn" id="home" href="/news" title="<%= t('partials.feed_action_bar.home') %>">
44
<i class="fa fa-reply"></i>
55
</a>
6-
<a class="btn" id="mark-all" title="<%= t('partials.action_bar.mark_all') %>">
6+
<a class="btn" id="mark-all" title="<%= t('partials.action_bar.mark_all') %>" data-action="click->mark-all-as-read#submit" data-hotkeys-target="click" data-hotkey="A">
77
<i class="fa fa-check"></i>
88
<%= render "stories/mark_all_as_read_form", {stories: stories} %>
99
</a>
10-
<a class="btn" href="<%= "/feed/#{@feed.id}" %>" id="refresh" title="<%= t('partials.action_bar.refresh') %>">
10+
<a class="btn" href="<%= "/feed/#{@feed.id}" %>" id="refresh" title="<%= t('partials.action_bar.refresh') %>" data-hotkeys-target="click" data-hotkey="r">
1111
<i class="fa fa-refresh"></i>
1212
</a>
1313
</div>
@@ -22,32 +22,8 @@
2222
<a class="btn btn-primary" id="feeds" href="/feeds" title="<%= t('partials.action_bar.view_feeds') %>">
2323
<i class="fa fa-list"></i>
2424
</a>
25-
<a class="btn btn-primary" id="add-feed" href="/feeds/new" title="<%= t('partials.action_bar.add_feed') %>">
25+
<a class="btn btn-primary" id="add-feed" href="/feeds/new" title="<%= t('partials.action_bar.add_feed') %>" data-hotkeys-target="click" data-hotkey="a">
2626
<i class="fa fa-plus"></i>
2727
</a>
2828
</div>
2929
</div>
30-
31-
<script type="text/javascript">
32-
$(document).ready(function() {
33-
$("#mark-all").click(function(e) {
34-
e.preventDefault();
35-
36-
$("form#mark-all-as-read").submit();
37-
});
38-
39-
Mousetrap.bind("r", function() {
40-
var refresh = $("a#refresh")[0];
41-
if (refresh) refresh.click();
42-
});
43-
44-
Mousetrap.bind("a", function() {
45-
var add_feed = $("a#add-feed")[0];
46-
if (add_feed) add_feed.click();
47-
});
48-
49-
Mousetrap.bind("shift+a", function() {
50-
$("form#mark-all-as-read").submit();
51-
});
52-
});
53-
</script>
Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
<nav>
1+
<nav data-controller="hotkeys mark-all-as-read" data-action="keydown@document->hotkeys#handleKeydown">
22
<div>
3-
<button class="btn" id="mark-all" title="<%= t('partials.action_bar.mark_all') %>" aria-label="<%= t('partials.action_bar.mark_all') %>">
3+
<button class="btn" id="mark-all" title="<%= t('partials.action_bar.mark_all') %>" aria-label="<%= t('partials.action_bar.mark_all') %>" data-action="click->mark-all-as-read#submit" data-hotkeys-target="click" data-hotkey="A">
44
<i class="fa fa-check"></i>
55
<%= render "stories/mark_all_as_read_form", { stories: stories } %>
66
</button>
7-
<a class="btn" href="/" id="refresh" title="<%= t('partials.action_bar.refresh') %>">
7+
<a class="btn" href="/" id="refresh" title="<%= t('partials.action_bar.refresh') %>" data-hotkeys-target="click" data-hotkey="r">
88
<i class="fa fa-refresh"></i>
99
</a>
1010
</div>
@@ -20,40 +20,11 @@
2020
<a class="btn btn-primary" id="archive" href="/archive" title="<%= t('partials.action_bar.archived_stories') %>">
2121
<i class="fa fa-clock-o"></i>
2222
</a>
23-
<a class="btn btn-primary" id="feeds" href="/feeds" title="<%= t('partials.action_bar.view_feeds') %>">
23+
<a class="btn btn-primary" id="feeds" href="/feeds" title="<%= t('partials.action_bar.view_feeds') %>" data-hotkeys-target="click" data-hotkey="f">
2424
<i class="fa fa-list"></i>
2525
</a>
26-
<a class="btn btn-primary" id="add-feed" href="/feeds/new" title="<%= t('partials.action_bar.add_feed') %>">
26+
<a class="btn btn-primary" id="add-feed" href="/feeds/new" title="<%= t('partials.action_bar.add_feed') %>" data-hotkeys-target="click" data-hotkey="a">
2727
<i class="fa fa-plus"></i>
2828
</a>
2929
</div>
3030
</nav>
31-
32-
<script type="text/javascript">
33-
$(document).ready(function() {
34-
$("#mark-all").click(function(e) {
35-
e.preventDefault();
36-
37-
$("form#mark-all-as-read").submit();
38-
});
39-
40-
Mousetrap.bind("r", function() {
41-
var refresh = $("a#refresh")[0];
42-
if (refresh) refresh.click();
43-
});
44-
45-
Mousetrap.bind("f", function() {
46-
var all_feeds = $("a#feeds")[0];
47-
if (all_feeds) all_feeds.click();
48-
});
49-
50-
Mousetrap.bind("a", function() {
51-
var add_feed = $("a#add-feed")[0];
52-
if (add_feed) add_feed.click();
53-
});
54-
55-
Mousetrap.bind("shift+a", function() {
56-
$("form#mark-all-as-read").submit();
57-
});
58-
});
59-
</script>

app/views/stories/_mark_all_as_read_form.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="hide">
2-
<%= form_with(url: "/stories/mark_all_as_read", id: "mark-all-as-read") do %>
2+
<%= form_with(url: "/stories/mark_all_as_read", id: "mark-all-as-read", data: { "mark-all-as-read-target": "form" }) do %>
33
<% stories.each do |story| %>
44
<input type="hidden" name="story_ids[]" value="<%= story.id %>" />
55
<% end %>

app/views/stories/archived.html.erb

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,41 +10,19 @@
1010
</ul>
1111
</div>
1212

13-
<div id="pagination">
13+
<div id="pagination" data-controller="hotkeys" data-action="keydown@document->hotkeys#handleKeydown">
1414
<% if @read_stories.previous_page %>
15-
<a id="prev_page" href="?page=<%= @read_stories.previous_page %>"><%= t('archive.previous') %></a>
15+
<a id="prev_page" href="?page=<%= @read_stories.previous_page %>" data-hotkeys-target="click" data-hotkey="ArrowLeft"><%= t('archive.previous') %></a>
1616
<% end %>
1717

1818
<% if @read_stories.total_pages > 1 %>
1919
<%= @read_stories.current_page %> <%= t('archive.of') %> <%= @read_stories.total_pages %>
2020
<% end %>
2121

2222
<% if @read_stories.next_page %>
23-
<a id="next_page" href="?page=<%= @read_stories.next_page %>"><%= t('archive.next') %></a>
23+
<a id="next_page" href="?page=<%= @read_stories.next_page %>" data-hotkeys-target="click" data-hotkey="ArrowRight"><%= t('archive.next') %></a>
2424
<% end %>
2525
</div>
26-
27-
<script>
28-
$(document).ready(function() {
29-
var stripQuerystring = function(full_url) {
30-
return full_url.split("?")[0];
31-
};
32-
33-
Mousetrap.bind("left", function() {
34-
var pageNumber = $("#prev_page").attr("href");
35-
36-
if (pageNumber)
37-
location.href = stripQuerystring(location.href) + pageNumber;
38-
});
39-
40-
Mousetrap.bind("right", function() {
41-
var pageNumber = $("#next_page").attr("href");
42-
43-
if (pageNumber)
44-
location.href = stripQuerystring(location.href) + pageNumber;
45-
});
46-
});
47-
</script>
4826
<% else %>
4927
<div id="sorry">
5028
<p><%= t('archive.sorry') %></p>

app/views/stories/starred.html.erb

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,20 @@
1010
</ul>
1111
</div>
1212

13-
<div id="pagination">
13+
<div id="pagination" data-controller="hotkeys" data-action="keydown@document->hotkeys#handleKeydown">
1414
<% if @starred_stories.previous_page %>
15-
<a id="prev_page" href="?page=<%= @starred_stories.previous_page %>"><%= t('starred.previous') %></a>
15+
<a id="prev_page" href="?page=<%= @starred_stories.previous_page %>" data-hotkeys-target="click" data-hotkey="ArrowLeft"><%= t('starred.previous') %></a>
1616
<% end %>
1717

1818
<% if @starred_stories.total_pages > 1 %>
1919
<%= @starred_stories.current_page %> <%= t('starred.of') %> <%= @starred_stories.total_pages %>
2020
<% end %>
2121

2222
<% if @starred_stories.next_page %>
23-
<a id="next_page" href="?page=<%= @starred_stories.next_page %>"><%= t('starred.next') %></a>
23+
<a id="next_page" href="?page=<%= @starred_stories.next_page %>" data-hotkeys-target="click" data-hotkey="ArrowRight"><%= t('starred.next') %></a>
2424
<% end %>
2525
</div>
2626

27-
<script>
28-
$(document).ready(function() {
29-
var stripQuerystring = function(full_url) {
30-
return full_url.split("?")[0];
31-
};
32-
33-
Mousetrap.bind("left", function() {
34-
var pageNumber = $("#prev_page").attr("href");
35-
36-
if (pageNumber)
37-
location.href = stripQuerystring(location.href) + pageNumber;
38-
});
39-
40-
Mousetrap.bind("right", function() {
41-
var pageNumber = $("#next_page").attr("href");
42-
43-
if (pageNumber)
44-
location.href = stripQuerystring(location.href) + pageNumber;
45-
});
46-
});
47-
</script>
48-
4927
<% else %>
5028
<div id="sorry">
5129
<p><%= t('starred.sorry') %></p>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {bootStimulus, getController} from "support/stimulus";
2+
import Controller from "controllers/mark_all_as_read_controller";
3+
import {assert} from "helpers/assert";
4+
5+
const name = "mark-all-as-read";
6+
const sel = `[data-controller='${name}']`;
7+
const formSel = "form#mark-all-as-read";
8+
9+
// Static test fixture — safe to use innerHTML
10+
function setupDOM(): void {
11+
document.body.innerHTML = `
12+
<div data-controller="${name}">
13+
<button data-action="click->${name}#submit">
14+
Mark all
15+
</button>
16+
<form id="mark-all-as-read"
17+
data-mark-all-as-read-target="form">
18+
</form>
19+
</div>
20+
`;
21+
}
22+
23+
async function setupController(): Promise<void> {
24+
setupDOM();
25+
26+
await bootStimulus(name, Controller);
27+
}
28+
29+
function element(): HTMLElement {
30+
const el = document.querySelector<HTMLElement>(sel);
31+
32+
return assert(el);
33+
}
34+
35+
function controller(): Controller {
36+
return getController(element(), name, Controller);
37+
}
38+
39+
function form(): HTMLFormElement {
40+
const el = document.querySelector<HTMLFormElement>(formSel);
41+
42+
return assert(el);
43+
}
44+
45+
describe("submit", () => {
46+
it("submits the form and prevents default", async () => {
47+
await setupController();
48+
const submitSpy = vi.spyOn(form(), "requestSubmit");
49+
const event = new Event("click", {cancelable: true});
50+
51+
controller().submit(event);
52+
53+
expect(event.defaultPrevented).toBe(true);
54+
expect(submitSpy).toHaveBeenCalledWith();
55+
});
56+
});

0 commit comments

Comments
 (0)