From 099974ddefeadd9f239255393ee51ac7f2627134 Mon Sep 17 00:00:00 2001 From: Faldrian Date: Wed, 28 Jan 2015 15:17:21 +0100 Subject: [PATCH] Add shortcuts for reshare, expand Post and open first link in a post --- Changelog.md | 1 + .../javascripts/app/views/stream/shortcuts.js | 46 +++++-- .../faq_keyboard_shortcuts_tpl.jst.hbs | 3 + config/locales/diaspora/en.yml | 15 ++- .../app/views/stream/shortcuts_spec.js | 114 ++++++++++++++---- 5 files changed, 142 insertions(+), 37 deletions(-) diff --git a/Changelog.md b/Changelog.md index d66913373..affe1b032 100644 --- a/Changelog.md +++ b/Changelog.md @@ -154,6 +154,7 @@ diaspora.yml file**. The existing settings from 0.4.x and before will not work a * Hide user setting if the community spotlight is not enabled on the pod [#5562](https://github.com/diaspora/diaspora/pull/5562) * Add HTML view for pod statistics [#5464](https://github.com/diaspora/diaspora/pull/5464) * Added/Moved hide, block user, report and delete button in SPV [#5547](https://github.com/diaspora/diaspora/pull/5547) +* Added keyboard shortcuts r(reshare), m(expand Post), o(open first link in post) [#5602](https://github.com/diaspora/diaspora/pull/5602) # 0.4.1.2 diff --git a/app/assets/javascripts/app/views/stream/shortcuts.js b/app/assets/javascripts/app/views/stream/shortcuts.js index 9d07d42eb..70c473b7e 100644 --- a/app/assets/javascripts/app/views/stream/shortcuts.js +++ b/app/assets/javascripts/app/views/stream/shortcuts.js @@ -13,6 +13,9 @@ app.views.StreamShortcuts = { this.on('hotkey:gotoPrev', this.gotoPrev, this); this.on('hotkey:likeSelected', this.likeSelected, this); this.on('hotkey:commentSelected', this.commentSelected, this); + this.on('hotkey:reshareSelected', this.reshareSelected, this); + this.on('hotkey:expandSelected', this.expandSelected, this); + this.on('hotkey:openFirstLinkSelected', this.openFirstLinkSelected, this); }, _onHotkeyDown: function(event) { @@ -21,7 +24,7 @@ app.views.StreamShortcuts = { if(jQuery.inArray(event.target.type, textAcceptingInputTypes) > -1){ return; } - + // trigger the events based on what key was pressed switch (String.fromCharCode( event.which ).toLowerCase()) { case "j": @@ -33,7 +36,7 @@ app.views.StreamShortcuts = { default: } }, - + _onHotkeyUp: function(event) { //make sure that the user is not typing in an input field var textAcceptingInputTypes = ["textarea", "select", "text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", "datetime-local", "search", "color"]; @@ -49,6 +52,15 @@ app.views.StreamShortcuts = { case "l": this.trigger('hotkey:likeSelected'); break; + case "r": + this.trigger('hotkey:reshareSelected'); + break; + case "m": + this.trigger('hotkey:expandSelected'); + break; + case "o": + this.trigger('hotkey:openFirstLinkSelected'); + break; default: } }, @@ -57,7 +69,7 @@ app.views.StreamShortcuts = { // select next post: take the first post under the header var stream_elements = this.$('div.stream_element.loaded'); var posUser = window.pageYOffset; - + for (var i = 0; i < stream_elements.length; i++) { if(stream_elements[i].offsetTop>posUser+this._headerSize){ this.selectPost(stream_elements[i]); @@ -74,7 +86,7 @@ app.views.StreamShortcuts = { // select previous post: take the first post above the header var stream_elements = this.$('div.stream_element.loaded'); var posUser = window.pageYOffset; - + for (var i = stream_elements.length-1; i >=0; i--) { if(stream_elements[i].offsetTop 0) { + // click does only work with vanilla javascript + link[0].click(); + } + }, + selectPost: function(element){ //remove the selection and selected-class from all posts var selected=this.$('div.stream_element.loaded.shortcut_selected'); @@ -102,7 +130,7 @@ app.views.StreamShortcuts = { //move to new post window.scrollTo(window.pageXOffset, element.offsetTop-this._headerSize); //add the selection and selected-class to new post - element.className+=" shortcut_selected highlighted"; + element.className+=" shortcut_selected highlighted"; }, }; // @license-end diff --git a/app/assets/templates/faq_keyboard_shortcuts_tpl.jst.hbs b/app/assets/templates/faq_keyboard_shortcuts_tpl.jst.hbs index 1f3074bbd..033d14a8e 100644 --- a/app/assets/templates/faq_keyboard_shortcuts_tpl.jst.hbs +++ b/app/assets/templates/faq_keyboard_shortcuts_tpl.jst.hbs @@ -10,6 +10,9 @@
  • {{ keyboard_shortcuts_li2 }}
  • {{ keyboard_shortcuts_li3 }}
  • {{ keyboard_shortcuts_li4 }}
  • +
  • {{ keyboard_shortcuts_li5 }}
  • +
  • {{ keyboard_shortcuts_li6 }}
  • +
  • {{ keyboard_shortcuts_li7 }}
  • diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 8383718fa..e72610d26 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -565,13 +565,16 @@ en: filter_tags_q: "How can I filter/exclude some tags from my stream?" filter_tags_a: "This is not yet available directly through diaspora*, but some %{third_party_tools} have been written that might provide this." keyboard_shortcuts: + title: "Keyboard shortcuts" keyboard_shortcuts_q: "What keyboard shortcuts are available?" keyboard_shortcuts_a1: "In the stream view you can use the following keyboard shortcuts:" keyboard_shortcuts_li1: "j - jump to the next post" keyboard_shortcuts_li2: "k - jump to the previous post" keyboard_shortcuts_li3: "c - comment on the current post" keyboard_shortcuts_li4: "l - like the current post" - title: "Keyboard shortcuts" + keyboard_shortcuts_li5: "r - reshare the current post" + keyboard_shortcuts_li6: "m - expand the current post" + keyboard_shortcuts_li7: "o - open the first link in the current post" miscellaneous: title: "Miscellaneous" back_to_top_q: "Is there a quick way to go back to the top of a page after I scroll down?" @@ -825,15 +828,15 @@ en: subject: "Your diaspora* account has been flagged for removal due to inactivity" body: |- Hello, - + It looks as though you no longer want your account at %{pod_url}, as you haven't used it for %{after_days} days. To ensure our active users get the best performance from this diaspora* pod, we'd like to remove unwanted accounts from our database. - + We'd love you to stay part of diaspora*'s community, and you're welcome to keep your account live if you want to. - + If you want to keep your account live, all you need to do is to sign in to your account before %{remove_after}. When you sign in, take a moment to have a look around diaspora*. It has changed a lot since you last looked in, and we think you'll like the improvements we've made. Follow some #tags to find content you love. - + Sign in here: %{login_url}. If you've forgotten your sign-in details, you can ask for a reminder on that page. - + Hoping to see you again, The diaspora* email robot! diff --git a/spec/javascripts/app/views/stream/shortcuts_spec.js b/spec/javascripts/app/views/stream/shortcuts_spec.js index 59dcf75d7..d908f091b 100644 --- a/spec/javascripts/app/views/stream/shortcuts_spec.js +++ b/spec/javascripts/app/views/stream/shortcuts_spec.js @@ -1,27 +1,27 @@ describe("app.views.StreamShortcuts", function () { - + beforeEach(function() { - this.post1 = factory.post({author : factory.author({name : "Rebecca Black", id : 1492})}) - this.post2 = factory.post({author : factory.author({name : "John Stamos", id : 1987})}) - + this.post1 = factory.post({author : factory.author({name : "Rebecca Black", id : 1492})}); + this.post2 = factory.post({author : factory.author({name : "John Stamos", id : 1987})}); + this.stream = new app.models.Stream(); this.stream.add([this.post1, this.post2]); this.view = new app.views.Stream({model : this.stream}); - + this.view.render(); expect(this.view.$('div.stream_element.loaded').length).toBe(2); }); - + describe("loading the stream", function(){ it("should setup the shortcuts", function(){ - spyOn(this.view, 'setupShortcuts'); + spyOn(this.view, 'setupShortcuts'); this.view.initialize(); expect(this.view.setupShortcuts).toHaveBeenCalled(); }); - }); - - describe("pressing 'j'", function(){ - + }); + + describe("pressing 'j'", function(){ + it("should call 'gotoNext' if not pressed in an input field", function(){ spyOn(this.view, 'gotoNext'); this.view.initialize(); @@ -31,13 +31,13 @@ describe("app.views.StreamShortcuts", function () { this.view._onHotkeyDown(e); expect(this.view.gotoNext).toHaveBeenCalled(); }); - + it("'gotoNext' should call 'selectPost'", function(){ spyOn(this.view, 'selectPost'); this.view.gotoNext(); expect(this.view.selectPost).toHaveBeenCalled(); }); - + it("shouldn't do anything if the user types in an input field", function(){ spyOn(this.view, 'gotoNext'); spyOn(this.view, 'selectPost'); @@ -50,7 +50,7 @@ describe("app.views.StreamShortcuts", function () { expect(this.view.selectPost).not.toHaveBeenCalled(); }); }); - + describe("pressing 'k'", function(){ it("should call 'gotoPrev' if not pressed in an input field", function(){ @@ -62,13 +62,13 @@ describe("app.views.StreamShortcuts", function () { this.view._onHotkeyDown(e); expect(this.view.gotoPrev).toHaveBeenCalled(); }); - + it("'gotoPrev' should call 'selectPost'", function(){ spyOn(this.view, 'selectPost'); this.view.gotoPrev(); expect(this.view.selectPost).toHaveBeenCalled(); }); - + it("shouldn't do anything if the user types in an input field", function(){ spyOn(this.view, 'gotoPrev'); spyOn(this.view, 'selectPost'); @@ -81,7 +81,7 @@ describe("app.views.StreamShortcuts", function () { expect(this.view.selectPost).not.toHaveBeenCalled(); }); }); - + describe("pressing 'c'", function(){ it("should click on the comment-button if not pressed in an input field", function(){ @@ -93,7 +93,7 @@ describe("app.views.StreamShortcuts", function () { this.view._onHotkeyUp(e); expect(this.view.commentSelected).toHaveBeenCalled(); }); - + it("shouldn't do anything if the user types in an input field", function(){ spyOn(this.view, 'commentSelected'); this.view.initialize(); @@ -104,9 +104,9 @@ describe("app.views.StreamShortcuts", function () { expect(this.view.commentSelected).not.toHaveBeenCalled(); }); }); - + describe("pressing 'l'", function(){ - + it("should click on the like-button if not pressed in an input field", function(){ spyOn(this.view, 'likeSelected'); this.view.initialize(); @@ -116,7 +116,7 @@ describe("app.views.StreamShortcuts", function () { this.view._onHotkeyUp(e); expect(this.view.likeSelected).toHaveBeenCalled(); }); - + it("shouldn't do anything if the user types in an input field", function(){ spyOn(this.view, 'likeSelected'); this.view.initialize(); @@ -127,4 +127,74 @@ describe("app.views.StreamShortcuts", function () { expect(this.view.likeSelected).not.toHaveBeenCalled(); }); }); -}) + + describe("pressing 'r'", function(){ + + it("should click on the reshare-button if not pressed in an input field", function(){ + spyOn(this.view, 'reshareSelected'); + this.view.initialize(); + var e = $.Event("keyup", { which: 82, target: {type: "div"} }); + //verify that the test is correct + expect(String.fromCharCode( e.which ).toLowerCase()).toBe('r'); + this.view._onHotkeyUp(e); + expect(this.view.reshareSelected).toHaveBeenCalled(); + }); + + it("shouldn't do anything if the user types in an input field", function(){ + spyOn(this.view, 'reshareSelected'); + this.view.initialize(); + var e = $.Event("keyup", { which: 82, target: {type: "textarea"} }); + //verify that the test is correct + expect(String.fromCharCode( e.which ).toLowerCase()).toBe('r'); + this.view._onHotkeyUp(e); + expect(this.view.reshareSelected).not.toHaveBeenCalled(); + }); + }); + + describe("pressing 'm'", function(){ + + it("should click on the more-button if not pressed in an input field", function(){ + spyOn(this.view, 'expandSelected'); + this.view.initialize(); + var e = $.Event("keyup", { which: 77, target: {type: "div"} }); + //verify that the test is correct + expect(String.fromCharCode( e.which ).toLowerCase()).toBe('m'); + this.view._onHotkeyUp(e); + expect(this.view.expandSelected).toHaveBeenCalled(); + }); + + it("shouldn't do anything if the user types in an input field", function(){ + spyOn(this.view, 'expandSelected'); + this.view.initialize(); + var e = $.Event("keyup", { which: 77, target: {type: "textarea"} }); + //verify that the test is correct + expect(String.fromCharCode( e.which ).toLowerCase()).toBe('m'); + this.view._onHotkeyUp(e); + expect(this.view.expandSelected).not.toHaveBeenCalled(); + }); + }); + + describe("pressing 'o'", function(){ + + it("should click on the more-button if not pressed in an input field", function(){ + spyOn(this.view, 'openFirstLinkSelected'); + this.view.initialize(); + var e = $.Event("keyup", { which: 79, target: {type: "div"} }); + //verify that the test is correct + expect(String.fromCharCode( e.which ).toLowerCase()).toBe('o'); + this.view._onHotkeyUp(e); + expect(this.view.openFirstLinkSelected).toHaveBeenCalled(); + }); + + it("shouldn't do anything if the user types in an input field", function(){ + spyOn(this.view, 'openFirstLinkSelected'); + this.view.initialize(); + var e = $.Event("keyup", { which: 79, target: {type: "textarea"} }); + //verify that the test is correct + expect(String.fromCharCode( e.which ).toLowerCase()).toBe('o'); + this.view._onHotkeyUp(e); + expect(this.view.openFirstLinkSelected).not.toHaveBeenCalled(); + }); + }); +}); +