FEATURE: Shortcut 'g s' goes to first suggested topic

FEATURE: Shortcut ‘g s’ goes to first suggested topic

diff --git a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6
index 615949c..fb69080 100644
--- a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6
+++ b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6
@@ -1,6 +1,7 @@
 import DiscourseURL from "discourse/lib/url";
 import Composer from "discourse/models/composer";
 import { minimumOffset } from "discourse/lib/offset-calculator";
+import { ajax } from "discourse/lib/ajax";
 
 const bindings = {
   "!": { postAction: "showFlags" },
@@ -32,6 +33,7 @@ const bindings = {
   "g p": { path: "/my/activity" },
   "g m": { path: "/my/messages" },
   "g d": { path: "/my/activity/drafts" },
+  "g s": { handler: "goToFirstSuggestedTopic", anonymous: true },
   home: { handler: "goToFirstPost", anonymous: true },
   "command+up": { handler: "goToFirstPost", anonymous: true },
   j: { handler: "selectDown", anonymous: true },
@@ -133,6 +135,26 @@ export default {
     Ember.run.later(() => $(".d-editor .quote").click(), 500);
   },
 
+  goToFirstSuggestedTopic() {
+    const $el = $(".suggested-topics a.raw-topic-link:first");
+    if ($el.length) {
+      $el.click();
+    } else {
+      const controller = this.container.lookup("controller:topic");
+      // Only the last page contains list of suggested topics.
+      const url = `/t/${controller.get("model.id")}/last.json`;
+      ajax(url).then(result => {
+        if (result.suggested_topics && result.suggested_topics.length > 0) {
+          const topic = controller.store.createRecord(
+            "topic",
+            result.suggested_topics[0]
+          );
+          DiscourseURL.routeTo(topic.get("url"));
+        }
+      });
+    }
+  },
+
   goToFirstPost() {
     this._jumpTo("jumpTop");
   },
diff --git a/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6 b/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6
new file mode 100644
index 0000000..ae77149
--- /dev/null
+++ b/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6
@@ -0,0 +1,64 @@
+import { acceptance } from "helpers/qunit-helpers";
+import DiscourseURL from "discourse/lib/url";
+
+acceptance("Keyboard Shortcuts", { loggedIn: true });
+
+test("go to first suggested topic", async assert => {
+  server.get("/t/27331/4.json", () => [
+    200,
+    { "Content-Type": "application/json" },
+    {}
+  ]);
+
+  server.get("/t/27331.json", () => [
+    200,
+    { "Content-Type": "application/json" },
+    {}
+  ]);
+
+  /*
+   * No suggested topics exist.
+   */
+
+  server.get("/t/9/last.json", () => [
+    200,
+    { "Content-Type": "application/json" },
+    {}
+  ]);
+
+  await visit("/t/this-is-a-test-topic/9");
+  await keyEvent(document, "keypress", "g".charCodeAt(0));
+  await keyEvent(document, "keypress", "s".charCodeAt(0));
+  assert.equal(currentURL(), "/t/this-is-a-test-topic/9");
+
+  /*
+   * Suggested topics elements exist.
+   */
+
+  await visit("/t/internationalization-localization/280");
+  await keyEvent(document, "keypress", "g".charCodeAt(0));
+  await keyEvent(document, "keypress", "s".charCodeAt(0));
+  assert.equal(currentURL(), "/t/polls-are-still-very-buggy/27331/4");
+
+  /*
+   * Suggested topic is returned by server.
+   */
+
+  server.get("/t/28830/last.json", () => [
+    200,
+    { "Content-Type": "application/json" },
+    {
+      suggested_topics: [
+        {
+          id: 27331,
+          slug: "keyboard-shortcuts-are-awesome"
+        }
+      ]
+    }
+  ]);
+
+  await visit("/t/1-3-0beta9-no-rate-limit-popups/28830");
+  await keyEvent(document, "keypress", "g".charCodeAt(0));
+  await keyEvent(document, "keypress", "s".charCodeAt(0));
+  assert.equal(currentURL(), "/t/keyboard-shortcuts-are-awesome/27331");
+});
diff --git a/test/javascripts/fixtures/topic.js.es6 b/test/javascripts/fixtures/topic.js.es6
index 1a71861..e086910 100644
--- a/test/javascripts/fixtures/topic.js.es6
+++ b/test/javascripts/fixtures/topic.js.es6
@@ -2321,222 +2321,6 @@ export default {
           post_count: 1
         }
       ],
-      suggested_topics: [
-        {
-          id: 27331,
-          title: "Polls are still very buggy",
-          fancy_title: "Polls are still very buggy",
-          slug: "polls-are-still-very-buggy",
-          posts_count: 4,
-          reply_count: 1,
-          highest_post_number: 4,
-          image_url:
-            "/uploads/default/_optimized/cd1/b8c/c162528887_690x401.png",
-          created_at: "2015-04-08T09:51:00.357Z",
-          last_posted_at: "2015-04-08T15:59:16.258Z",
-          bumped: true,
-          bumped_at: "2015-04-08T16:05:09.842Z",
-          unseen: false,
-          last_read_post_number: 3,
-          unread: 0,
-          new_posts: 1,
-          pinned: false,
-          unpinned: null,
-          visible: true,
-          closed: false,
-          archived: false,
-          notification_level: 2,
-          bookmarked: false,
-          liked: false,
-          archetype: "regular",
-          like_count: 11,
-          views: 55,
-          category_id: 1
-        },
-        {
-          id: 27343,
-          title:
-            "Mobile theme doesn't show last activity time for topics on category page",
-          fancy_title:
-            "Mobile theme doesn’t show last activity time for topics on category page",
-          slug:
-            "mobile-theme-doesnt-show-last-activity-time-for-topics-on-category-page",
-          posts_count: 4,
-          reply_count: 2,
-          highest_post_number: 4,
-          image_url:
-            "/uploads/default/_optimized/13e/25c/bd30b466be_281x500.png",
-          created_at: "2015-04-08T14:20:51.177Z",
-          last_posted_at: "2015-04-08T15:40:30.037Z",
-          bumped: true,
-          bumped_at: "2015-04-08T15:40:30.037Z",
-          unseen: false,
-          last_read_post_number: 2,
-          unread: 0,
-          new_posts: 2,
-          pinned: false,
-          unpinned: null,
-          visible: true,
-          closed: false,
-          archived: false,
-          notification_level: 2,
-          bookmarked: false,
-          liked: false,
-          archetype: "regular",
-          like_count: 3,
-          views: 23,
-          category_id: 9
-        },
-        {
-          id: 27346,
-          title:
-            'Reply+{messagekey}@... optionaly in header "from" in addition to "reply-to"',
-          fancy_title:
-            "Reply+{messagekey}@… optionaly in header “from” in addition to “reply-to”",
-          slug:
-            "reply-messagekey-optionaly-in-header-from-in-addition-to-reply-to",
-          posts_count: 1,
-          reply_count: 0,
-          highest_post_number: 1,
-          image_url: null,
-          created_at: "2015-04-08T16:05:13.103Z",
-          last_posted_at: "2015-04-08T16:05:13.415Z",
-          bumped: true,
-          bumped_at: "2015-04-08T16:05:13.415Z",
-          unseen: true,
-          pinned: false,
-          unpinned: null,
-          visible: true,
-          closed: false,
-          archived: false,
-          bookmarked: null,
-          liked: null,
-          archetype: "regular",
-          like_count: 0,
-          views: 8,
-          category_id: 2
-        },
-        {
-          id: 19670,
-          title: "Parsing (Oneboxing) IMDB links",
-          fancy_title: "Parsing (Oneboxing) IMDB links",
-          slug: "parsing-oneboxing-imdb-links",
-          posts_count: 8,
-          reply_count: 1,
-          highest_post_number: 8,
-          image_url: null,
-          created_at: "2014-09-05T07:19:26.161Z",
-          last_posted_at: "2015-04-07T09:21:21.570Z",
-          bumped: true,
-          bumped_at: "2015-04-07T09:21:21.570Z",
-          unseen: false,
-          last_read_post_number: 8,
-          unread: 0,
-          new_posts: 0,
-          pinned: false,
-          unpinned: null,
-          visible: true,
-          closed: false,

[... diff too long, it was truncated ...]

GitHub sha: fc4c015b

1 Like