Skip to content

Commit

Permalink
Refactor stream shortcuts
Browse files Browse the repository at this point in the history
closes #7127
  • Loading branch information
svbergerem authored and denschub committed Sep 29, 2016
1 parent 0a264c1 commit 35aa0ba
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 109 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Note: Although this is a minor release, the configuration file changed because t
* Refactored post interactions on the single post view [#7089](https://github.com/diaspora/diaspora/pull/7089)
* Extract inline JavaScript [#7113](https://github.com/diaspora/diaspora/pull/7113)
* Port conversations inbox to backbone.js [#7108](https://github.com/diaspora/diaspora/pull/7108)
* Refactored stream shortcuts for more flexibility [#7127](https://github.com/diaspora/diaspora/pull/7127)

## Bug fixes
* Post comments no longer get collapsed when interacting with a post [#7040](https://github.com/diaspora/diaspora/pull/7040)
Expand Down
31 changes: 31 additions & 0 deletions app/assets/javascripts/app/helpers/shortcuts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
(function() {
app.helpers.Shortcuts = function(evtname, fn) {
var textAcceptingInputTypes = [
"color",
"date",
"datetime",
"datetime-local",
"email",
"month",
"number",
"password",
"range",
"search",
"select",
"text",
"textarea",
"time",
"url",
"week"
];

$("body").on(evtname, function(event) {
// make sure that the user is not typing in an input field
if (textAcceptingInputTypes.indexOf(event.target.type) === -1) {
fn(event);
}
});
};
})();
// @license-end
18 changes: 3 additions & 15 deletions app/assets/javascripts/app/views/stream/shortcuts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@
app.views.StreamShortcuts = Backbone.View.extend({
_headerSize: 60,

events: {
"keydown": "_onHotkeyDown",
"keyup": "_onHotkeyUp"
initialize: function() {
app.helpers.Shortcuts("keydown", this._onHotkeyDown.bind(this));
app.helpers.Shortcuts("keyup", this._onHotkeyUp.bind(this));
},

_onHotkeyDown: 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"];
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":
Expand All @@ -28,12 +22,6 @@ app.views.StreamShortcuts = Backbone.View.extend({
},

_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"];
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 "c":
Expand Down
17 changes: 17 additions & 0 deletions spec/javascripts/app/helpers/shortcuts_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
describe("app.helpers.Shortcuts", function() {
it("calls the function when the event has been fired outside of an input field", function() {
var spy = jasmine.createSpy();
spec.content().append("<div class='hotkey-div'></div>");
app.helpers.Shortcuts("keydown", spy);
$(".hotkey-div").trigger("keydown");
expect(spy).toHaveBeenCalled();
});

it("doesn't call the function when the event has been fired in an input field", function() {
var spy = jasmine.createSpy();
spec.content().append("<textarea class='hotkey-textarea'></textarea>");
app.helpers.Shortcuts("keydown", spy);
$(".hotkey-textarea").trigger("keydown");
expect(spy).not.toHaveBeenCalled();
});
});
152 changes: 58 additions & 94 deletions spec/javascripts/app/views/stream/shortcuts_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,131 +13,95 @@ describe("app.views.StreamShortcuts", function () {
expect(spec.content().find("div.stream-element.loaded").length).toBe(2);
});

describe("pressing 'j'", function(){
it("should call 'gotoNext' if not pressed in an input field", function(){
spyOn(this.view, 'gotoNext');
var e = $.Event("keydown", { which: Keycodes.J, target: {type: "div"} });
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');
var e = $.Event("keydown", { which: Keycodes.J, target: {type: "textarea"} });
this.view._onHotkeyDown(e);
expect(this.view.gotoNext).not.toHaveBeenCalled();
expect(this.view.selectPost).not.toHaveBeenCalled();
describe("initialize", function() {
it("setups the shortcuts", function() {
spyOn(app.helpers, "Shortcuts").and.callThrough();
spyOn(app.views.StreamShortcuts.prototype, "_onHotkeyDown");
spyOn(app.views.StreamShortcuts.prototype, "_onHotkeyUp");
this.view = new app.views.StreamShortcuts({el: $(document)});
expect(app.helpers.Shortcuts.calls.count()).toBe(2);

$("body").trigger($.Event("keydown", {which: Keycodes.J, target: {type: "textarea"}}));
$("body").trigger($.Event("keyup", {which: Keycodes.J, target: {type: "textarea"}}));
expect(app.views.StreamShortcuts.prototype._onHotkeyDown).not.toHaveBeenCalled();
expect(app.views.StreamShortcuts.prototype._onHotkeyUp).not.toHaveBeenCalled();

var e = $.Event("keydown", {which: Keycodes.J, target: {type: "div"}});
$("body").trigger(e);
expect(app.views.StreamShortcuts.prototype._onHotkeyDown).toHaveBeenCalledWith(e);

e = $.Event("keyup", {which: Keycodes.J, target: {type: "div"}});
$("body").trigger(e);
expect(app.views.StreamShortcuts.prototype._onHotkeyUp).toHaveBeenCalledWith(e);
});
});

describe("pressing 'k'", function(){
it("should call 'gotoPrev' if not pressed in an input field", function(){
spyOn(this.view, 'gotoPrev');
var e = $.Event("keydown", { which: Keycodes.K, target: {type: "div"} });
describe("_onHotkeyDown", function() {
it("calls goToNext when the user pressed 'J'", function() {
spyOn(this.view, "gotoNext");
var e = $.Event("keydown", {which: Keycodes.J, target: {type: "div"}});
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();
expect(this.view.gotoNext).toHaveBeenCalled();
});

it("shouldn't do anything if the user types in an input field", function(){
spyOn(this.view, 'gotoPrev');
spyOn(this.view, 'selectPost');
var e = $.Event("keydown", { which: Keycodes.K, target: {type: "textarea"} });
it("calls gotoPrev when the user pressed 'K'", function() {
spyOn(this.view, "gotoPrev");
var e = $.Event("keydown", {which: Keycodes.K, target: {type: "div"}});
this.view._onHotkeyDown(e);
expect(this.view.gotoPrev).not.toHaveBeenCalled();
expect(this.view.selectPost).not.toHaveBeenCalled();
expect(this.view.gotoPrev).toHaveBeenCalled();
});
});

describe("pressing 'c'", function(){
it("should click on the comment-button if not pressed in an input field", function(){
spyOn(this.view, 'commentSelected');
var e = $.Event("keyup", { which: Keycodes.C, target: {type: "div"} });
describe("_onHotkeyUp", function() {
it("calls commentSelected when the user pressed 'C'", function() {
spyOn(this.view, "commentSelected");
var e = $.Event("keyup", {which: Keycodes.C, target: {type: "div"}});
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');
var e = $.Event("keyup", { which: Keycodes.C, target: {type: "textarea"} });
this.view._onHotkeyUp(e);
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');
var e = $.Event("keyup", { which: Keycodes.L, target: {type: "div"} });
it("calls likeSelected when the user pressed 'L'", function() {
spyOn(this.view, "likeSelected");
var e = $.Event("keyup", {which: Keycodes.L, target: {type: "div"}});
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');
var e = $.Event("keyup", { which: Keycodes.L, target: {type: "textarea"} });
it("calls expandSelected when the user pressed 'M'", function() {
spyOn(this.view, "expandSelected");
var e = $.Event("keyup", {which: Keycodes.M, target: {type: "div"}});
this.view._onHotkeyUp(e);
expect(this.view.likeSelected).not.toHaveBeenCalled();
expect(this.view.expandSelected).toHaveBeenCalled();
});
});

describe("pressing 'r'", function(){
it("should click on the reshare-button if not pressed in an input field", function(){
spyOn(this.view, 'reshareSelected');
var e = $.Event("keyup", { which: Keycodes.R, target: {type: "div"} });
it("calls openFirstLinkSelected when the user pressed 'O'", function() {
spyOn(this.view, "openFirstLinkSelected");
var e = $.Event("keyup", {which: Keycodes.O, target: {type: "div"}});
this.view._onHotkeyUp(e);
expect(this.view.reshareSelected).toHaveBeenCalled();
expect(this.view.openFirstLinkSelected).toHaveBeenCalled();
});

it("shouldn't do anything if the user types in an input field", function(){
spyOn(this.view, 'reshareSelected');
var e = $.Event("keyup", { which: Keycodes.R, target: {type: "textarea"} });
it("calls reshareSelected when the user pressed 'R'", function() {
spyOn(this.view, "reshareSelected");
var e = $.Event("keyup", {which: Keycodes.R, target: {type: "div"}});
this.view._onHotkeyUp(e);
expect(this.view.reshareSelected).not.toHaveBeenCalled();
expect(this.view.reshareSelected).toHaveBeenCalled();
});
});

describe("pressing 'm'", function(){
it("should click on the more-button if not pressed in an input field", function(){
spyOn(this.view, 'expandSelected');
var e = $.Event("keyup", { which: Keycodes.M, target: {type: "div"} });
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');
var e = $.Event("keyup", { which: Keycodes.M, target: {type: "textarea"} });
this.view._onHotkeyUp(e);
expect(this.view.expandSelected).not.toHaveBeenCalled();
describe("gotoNext", function() {
it("calls selectPost", function() {
spyOn(this.view, "selectPost");
this.view.gotoNext();
expect(this.view.selectPost).toHaveBeenCalled();
});
});

describe("pressing 'o'", function(){
it("should click on the more-button if not pressed in an input field", function(){
spyOn(this.view, 'openFirstLinkSelected');
var e = $.Event("keyup", { which: Keycodes.O, target: {type: "div"} });
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');
var e = $.Event("keyup", { which: Keycodes.O, target: {type: "textarea"} });
this.view._onHotkeyUp(e);
expect(this.view.openFirstLinkSelected).not.toHaveBeenCalled();
describe("gotoPrev", function() {
it("calls selectPost", function() {
spyOn(this.view, "selectPost");
this.view.gotoPrev();
expect(this.view.selectPost).toHaveBeenCalled();
});
});
});

0 comments on commit 35aa0ba

Please sign in to comment.