Skip to content
Browse files

Added keyboard navigation (arrows move, enter votes)

  • Loading branch information...
1 parent d47f4f4 commit 7422530a01047cc04e676d14ce7b25d4c93148a2 @lukeledet committed May 6, 2012
View
4 app/assets/javascripts/keymaster.js
@@ -0,0 +1,4 @@
+// keymaster.js
+// (c) 2011 Thomas Fuchs
+// keymaster.js may be freely distributed under the MIT license.
+(function(a){function h(a,b){var c=a.length;while(c--)if(a[c]===b)return c;return-1}function i(a){var b,g,i,j,k;b=a.keyCode;if(b==93||b==224)b=91;if(b in d){d[b]=!0;for(i in f)f[i]==b&&(l[i]=!0);return}if(!l.filter.call(this,a))return;if(!(b in c))return;for(j=0;j<c[b].length;j++){g=c[b][j];if(g.scope==e||g.scope=="all"){k=g.mods.length>0;for(i in d)if(!d[i]&&h(g.mods,+i)>-1||d[i]&&h(g.mods,+i)==-1)k=!1;(g.mods.length==0&&!d[16]&&!d[18]&&!d[17]&&!d[91]||k)&&g.method(a,g)===!1&&(a.preventDefault?a.preventDefault():a.returnValue=!1,a.stopPropagation&&a.stopPropagation(),a.cancelBubble&&(a.cancelBubble=!0))}}}function j(a){var b=a.keyCode,c;if(b==93||b==224)b=91;if(b in d){d[b]=!1;for(c in f)f[c]==b&&(l[c]=!1)}}function k(){for(b in d)d[b]=!1;for(b in f)l[b]=!1}function l(a,b,d){var e,h,i,j;d===undefined&&(d=b,b="all"),a=a.replace(/\s/g,""),e=a.split(","),e[e.length-1]==""&&(e[e.length-2]+=",");for(i=0;i<e.length;i++){h=[],a=e[i].split("+");if(a.length>1){h=a.slice(0,a.length-1);for(j=0;j<h.length;j++)h[j]=f[h[j]];a=[a[a.length-1]]}a=a[0],a=g[a]||a.toUpperCase().charCodeAt(0),a in c||(c[a]=[]),c[a].push({shortcut:e[i],scope:b,method:d,key:e[i],mods:h})}}function m(a){var b=(a.target||a.srcElement).tagName;return b!="INPUT"&&b!="SELECT"&&b!="TEXTAREA"}function n(a){e=a||"all"}function o(){return e||"all"}function p(a){var b,d,e;for(b in c){d=c[b];for(e=0;e<d.length;)d[e].scope===a?d.splice(e,1):e++}}function q(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,function(){c(window.event)})}var b,c={},d={16:!1,18:!1,17:!1,91:!1},e="all",f={"⇧":16,shift:16,"⌥":18,alt:18,option:18,"⌃":17,ctrl:17,control:17,"⌘":91,command:91},g={backspace:8,tab:9,clear:12,enter:13,"return":13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,"delete":46,home:36,end:35,pageup:33,pagedown:34,",":188,".":190,"/":191,"`":192,"-":189,"=":187,";":186,"'":222,"[":219,"]":221,"\\":220};for(b=1;b<20;b++)f["f"+b]=111+b;for(b in f)l[b]=!1;q(document,"keydown",i),q(document,"keyup",j),q(window,"focus",k),a.key=l,a.key.setScope=n,a.key.getScope=o,a.key.deleteScope=p,a.key.filter=m,typeof module!="undefined"&&(module.exports=key)})(this);
View
49 app/assets/javascripts/keys.js.coffee
@@ -0,0 +1,49 @@
+window.selected_song = null
+
+key.filter = (e) -> true
+
+key '/,s', ->
+ return if $('.navbar-search input').is(':focus')
+ $('.navbar-search input').focus()
+ return false
+
+key 'escape', 'searching', ->
+ cancel_search()
+ return false
+
+key 'down', ->
+ $('.navbar-search input').blur()
+ window.selected_song = if selected_song != null then selected_song + 1 else 1
+ window.selected_song = $('#song_list tr').length - 1 if selected_song >= $('#song_list tr').length
+
+ $('#song_list tr').removeClass('selected')
+ $('#song_list tr:eq('+selected_song+')').addClass('selected')
+ return false
+
+key 'up', ->
+ return if $('.navbar-search input').is(':focus')
+
+ $('.navbar-search input').blur()
+ window.selected_song = if selected_song != null then selected_song - 1 else 1
+
+ if selected_song < 1
+ $('.navbar-search input').focus()
+ window.selected_song = null
+
+ $('#song_list tr').removeClass('selected')
+ $('#song_list tr:eq('+selected_song+')').addClass('selected')
+ return false
+
+key 'left', ->
+ return if $('.navbar-search input').is(':focus')
+ $('.pagination .prev a').click()
+ return false
+
+key 'right', ->
+ return if $('.navbar-search input').is(':focus')
+ $('.pagination .next_page a').click()
+ return false
+
+key 'enter', ->
+ return if $('.navbar-search input').is(':focus')
+ $('#song_list tr:eq('+selected_song+') a.vote').click()
View
15 app/assets/javascripts/songs.js.coffee
@@ -10,16 +10,25 @@ format_time = (seconds) ->
else
current = minutes + ':' + pad(seconds,2)
+window.cancel_search = ->
+ key.setScope('all')
+ $('.navbar-search input').val('').keyup().blur()
+ $('#cancel-search').hide()
+
jQuery ($) ->
- $('.search-query').on 'keyup', ->
+ $('.search-query')
+ .on 'keyup', (e) ->
+ return false if e.keyCode in [37..40]
+
$.ajax '/?query='+encodeURI(this.value.replace(/^\s+|\s+$/g,'')), {dataType: 'script'}
$('#cancel-search').show()
if this.value == ''
$('#cancel-search').hide()
+ .focus ->
+ key.setScope('searching')
$('#cancel-search').on 'click', ->
- $('.search-query').val('').keyup()
- $(this).hide()
+ cancel_search()
setInterval ->
return if elapsed == null
View
4 app/assets/stylesheets/songs.css.scss
@@ -23,4 +23,8 @@
.vote_column {
width: 120px;
}
+
+ tr.selected {
+ background-color: #f5f5f5;
+ }
}
View
2 app/views/songs/_song.html.erb
@@ -10,7 +10,7 @@
<% elsif song.playing? %>
<span class="label label-success">This song is playing!</span>
<% else %>
- <%= link_to 'Vote', new_song_vote_path(song), remote: true, class: 'btn btn-mini btn-primary', id: "vote_#{song.id}" %>
+ <%= link_to 'Vote', new_song_vote_path(song), remote: true, class: 'btn btn-mini btn-primary vote', id: "vote_#{song.id}" %>
<% end %>
</td>
</tr>
View
2 app/views/songs/_table.html.erb
@@ -9,4 +9,4 @@
<%= render @songs %>
</table>
-<%= paginate @songs, remote: params[:query].present? %>
+<%= paginate @songs, remote: true %>

0 comments on commit 7422530

Please sign in to comment.
Something went wrong with that request. Please try again.