Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ application.register("hotkeys", HotkeysController);
import KeepUnreadToggleController from "./keep_unread_toggle_controller";
application.register("keep-unread-toggle", KeepUnreadToggleController);

import MarkAllAsReadController from "./mark_all_as_read_controller";
application.register("mark-all-as-read", MarkAllAsReadController);

import StarToggleController from "./star_toggle_controller";
application.register("star-toggle", StarToggleController);
15 changes: 15 additions & 0 deletions app/javascript/controllers/mark_all_as_read_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Controller} from "@hotwired/stimulus";

import {assert} from "helpers/assert";

export default class extends Controller {
static override targets = ["form"];

formTarget!: HTMLFormElement;

submit(event: Event): void {
event.preventDefault();

assert(this.formTarget).requestSubmit();
}
}
32 changes: 4 additions & 28 deletions app/views/feeds/_single_feed_action_bar.html.erb
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<div class="row">
<div class="row" data-controller="hotkeys mark-all-as-read" data-action="keydown@document->hotkeys#handleKeydown">
<div class="pull-left">
<a class="btn" id="home" href="/news" title="<%= t('partials.feed_action_bar.home') %>">
<i class="fa fa-reply"></i>
</a>
<a class="btn" id="mark-all" title="<%= t('partials.action_bar.mark_all') %>">
<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">
<i class="fa fa-check"></i>
<%= render "stories/mark_all_as_read_form", {stories: stories} %>
</a>
<a class="btn" href="<%= "/feed/#{@feed.id}" %>" id="refresh" title="<%= t('partials.action_bar.refresh') %>">
<a class="btn" href="<%= "/feed/#{@feed.id}" %>" id="refresh" title="<%= t('partials.action_bar.refresh') %>" data-hotkeys-target="click" data-hotkey="r">
<i class="fa fa-refresh"></i>
</a>
</div>
Expand All @@ -22,32 +22,8 @@
<a class="btn btn-primary" id="feeds" href="/feeds" title="<%= t('partials.action_bar.view_feeds') %>">
<i class="fa fa-list"></i>
</a>
<a class="btn btn-primary" id="add-feed" href="/feeds/new" title="<%= t('partials.action_bar.add_feed') %>">
<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">
<i class="fa fa-plus"></i>
</a>
</div>
</div>

<script type="text/javascript">
$(document).ready(function() {
$("#mark-all").click(function(e) {
e.preventDefault();

$("form#mark-all-as-read").submit();
});

Mousetrap.bind("r", function() {
var refresh = $("a#refresh")[0];
if (refresh) refresh.click();
});

Mousetrap.bind("a", function() {
var add_feed = $("a#add-feed")[0];
if (add_feed) add_feed.click();
});

Mousetrap.bind("shift+a", function() {
$("form#mark-all-as-read").submit();
});
});
</script>
39 changes: 5 additions & 34 deletions app/views/stories/_action_bar.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<nav>
<nav data-controller="hotkeys mark-all-as-read" data-action="keydown@document->hotkeys#handleKeydown">
<div>
<button class="btn" id="mark-all" title="<%= t('partials.action_bar.mark_all') %>" aria-label="<%= t('partials.action_bar.mark_all') %>">
<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">
<i class="fa fa-check"></i>
<%= render "stories/mark_all_as_read_form", { stories: stories } %>
</button>
<a class="btn" href="/" id="refresh" title="<%= t('partials.action_bar.refresh') %>">
<a class="btn" href="/" id="refresh" title="<%= t('partials.action_bar.refresh') %>" data-hotkeys-target="click" data-hotkey="r">
<i class="fa fa-refresh"></i>
</a>
</div>
Expand All @@ -20,40 +20,11 @@
<a class="btn btn-primary" id="archive" href="/archive" title="<%= t('partials.action_bar.archived_stories') %>">
<i class="fa fa-clock-o"></i>
</a>
<a class="btn btn-primary" id="feeds" href="/feeds" title="<%= t('partials.action_bar.view_feeds') %>">
<a class="btn btn-primary" id="feeds" href="/feeds" title="<%= t('partials.action_bar.view_feeds') %>" data-hotkeys-target="click" data-hotkey="f">
<i class="fa fa-list"></i>
</a>
<a class="btn btn-primary" id="add-feed" href="/feeds/new" title="<%= t('partials.action_bar.add_feed') %>">
<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">
<i class="fa fa-plus"></i>
</a>
</div>
</nav>

<script type="text/javascript">
$(document).ready(function() {
$("#mark-all").click(function(e) {
e.preventDefault();

$("form#mark-all-as-read").submit();
});

Mousetrap.bind("r", function() {
var refresh = $("a#refresh")[0];
if (refresh) refresh.click();
});

Mousetrap.bind("f", function() {
var all_feeds = $("a#feeds")[0];
if (all_feeds) all_feeds.click();
});

Mousetrap.bind("a", function() {
var add_feed = $("a#add-feed")[0];
if (add_feed) add_feed.click();
});

Mousetrap.bind("shift+a", function() {
$("form#mark-all-as-read").submit();
});
});
</script>
2 changes: 1 addition & 1 deletion app/views/stories/_mark_all_as_read_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="hide">
<%= form_with(url: "/stories/mark_all_as_read", id: "mark-all-as-read") do %>
<%= form_with(url: "/stories/mark_all_as_read", id: "mark-all-as-read", data: { "mark-all-as-read-target": "form" }) do %>
<% stories.each do |story| %>
<input type="hidden" name="story_ids[]" value="<%= story.id %>" />
<% end %>
Expand Down
28 changes: 3 additions & 25 deletions app/views/stories/archived.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,19 @@
</ul>
</div>

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

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

<% if @read_stories.next_page %>
<a id="next_page" href="?page=<%= @read_stories.next_page %>"><%= t('archive.next') %></a>
<a id="next_page" href="?page=<%= @read_stories.next_page %>" data-hotkeys-target="click" data-hotkey="ArrowRight"><%= t('archive.next') %></a>
<% end %>
</div>

<script>
$(document).ready(function() {
var stripQuerystring = function(full_url) {
return full_url.split("?")[0];
};

Mousetrap.bind("left", function() {
var pageNumber = $("#prev_page").attr("href");

if (pageNumber)
location.href = stripQuerystring(location.href) + pageNumber;
});

Mousetrap.bind("right", function() {
var pageNumber = $("#next_page").attr("href");

if (pageNumber)
location.href = stripQuerystring(location.href) + pageNumber;
});
});
</script>
<% else %>
<div id="sorry">
<p><%= t('archive.sorry') %></p>
Expand Down
28 changes: 3 additions & 25 deletions app/views/stories/starred.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,20 @@
</ul>
</div>

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

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

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

<script>
$(document).ready(function() {
var stripQuerystring = function(full_url) {
return full_url.split("?")[0];
};

Mousetrap.bind("left", function() {
var pageNumber = $("#prev_page").attr("href");

if (pageNumber)
location.href = stripQuerystring(location.href) + pageNumber;
});

Mousetrap.bind("right", function() {
var pageNumber = $("#next_page").attr("href");

if (pageNumber)
location.href = stripQuerystring(location.href) + pageNumber;
});
});
</script>

<% else %>
<div id="sorry">
<p><%= t('starred.sorry') %></p>
Expand Down
56 changes: 56 additions & 0 deletions spec/javascript/controllers/mark_all_as_read_controller_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {bootStimulus, getController} from "support/stimulus";
import Controller from "controllers/mark_all_as_read_controller";
import {assert} from "helpers/assert";

const name = "mark-all-as-read";
const sel = `[data-controller='${name}']`;
const formSel = "form#mark-all-as-read";

// Static test fixture — safe to use innerHTML
function setupDOM(): void {
document.body.innerHTML = `
<div data-controller="${name}">
<button data-action="click->${name}#submit">
Mark all
</button>
<form id="mark-all-as-read"
data-mark-all-as-read-target="form">
</form>
</div>
`;
}

async function setupController(): Promise<void> {
setupDOM();

await bootStimulus(name, Controller);
}

function element(): HTMLElement {
const el = document.querySelector<HTMLElement>(sel);

return assert(el);
}

function controller(): Controller {
return getController(element(), name, Controller);
}

function form(): HTMLFormElement {
const el = document.querySelector<HTMLFormElement>(formSel);

return assert(el);
}

describe("submit", () => {
it("submits the form and prevents default", async () => {
await setupController();
const submitSpy = vi.spyOn(form(), "requestSubmit");
const event = new Event("click", {cancelable: true});

controller().submit(event);

expect(event.defaultPrevented).toBe(true);
expect(submitSpy).toHaveBeenCalledWith();
});
});