// Cleverly insert html for modal dialog into the body $(function() { $('body').append('<div><a href="#myModal" id="hotkeys" role="button" data-toggle="modal"></a> <div id="myModal" class="modal hotkeysModal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h3 id="myModalLabel">Keyboard Shortcuts</h3> </div> <div class="modal-body"> <table class="hotkeyhelp"> <thead> <h4> Main Navigation</h4> </thead> <tbody> <tr> <td> <span class="label">?</span> </td> <td> Show/Hide this menu </td> </tr> <tr> <td> <span class="label">1</span> </td> <td> Home </td> </tr> <tr> <td> <span class="label">2</span> </td> <td> Reviews </td> </tr> <tr> <td> <span class="label">3</span> </td> <td> Files </td> </tr> <tr> <td> <span class="label">4</span> </td> <td> History </td> </tr> <tr> <td> <span class="label">5</span> </td> <td> Jobs </td> </tr></tbody> </table> <table class="hotkeyhelp"> <thead> <h4> Browsing</h4> </thead> <tbody> <tr> <td> <span class="label">J</span> / <span class="label">K</span> </td> <td> Next / Previous Item </td> </tr> <tr> <td> <span class="label">Enter</span> </td> <td> Open selected content </td> </tr> <tr> <td> <span class="label">X</span> </td> <td> Show More/Less Description </td> </tr> </tbody> </table> <table class="hotkeyhelp"> <thead> <h4> Reviews, Changelists</h4> </thead> <tbody> <tr> <td> <span class="label">J</span> / <span class="label">K</span> </td> <td> Next / Previous File </td> </tr> <tr> <td> <span class="label">Enter</span> or <span class="label">X</span> </td> <td> Expand/Collapse Selected File </td> </tr> <tr> <td> <span class="label">N</span> / <span class="label">P</span> </td> <td> Next / Previous Diff Chunk </td> </tr> </tbody> </table></div> </div></div>'); }); var index = -1; var rowFocused = false; // when a key is pressed, do this $(window).on('keydown', function(e) { // don't act on already handled events or if the files tab isn't active if (e.ctrlKey || e.metaKey || e.isDefaultPrevented() || $('textarea').is(':focus') || $('input').is(':focus')) { return; } // Global Keyboard Shortcuts switch (e.which) { case 48: // 0: go to system info page if (e.altKey) { window.location = '/info/'; } break; case 49: // 1: go home window.location = '/'; break; case 50: // 2: go to reviews window.location = '/reviews/'; break; case 51: // 3: go to files window.location = '/files/'; break; case 52: // 4: go to history window.location = '/changes/'; break; case 53: // 5: go to jobs window.location = '/jobs/'; break; case 74: // J: focus next activity rowFocused = true; // Don't exceed number of rows if ($('#browse.active').length && (index >= $('.browse-files tbody tr').length-1)) { break; } if ($('tr[data-id]').length && (index >= $('tr[data-id]').length-1)) { break; } if ($('.diff-wrapper').length && (index >= $('.diff-wrapper').length-1)) { break; } index += 1; break; case 75: // K: focus previous activity if (index>0) { index = index-1; rowFocused = true; } break; case 191: // ?: toggle keyboard shortcuts menu if (e.shiftKey) { $('#hotkeys').trigger('click'); } break; } // Home Page Keyboard Shortcuts if ($('.activity-stream.stream-global').length) { switch (e.which) { case 13: // ENTER: go to content related to focused activity if ($('.row-main.active .activity-body a:nth(1)').length) { window.location = $('.row-main.active .activity-body a:nth(1)').attr('href'); } else { window.location = $('.row-main.active .activity-body a:nth(0)').attr('href'); } break; case 88: // X: read more/less focused activity if ($('.row-main.active .expanded').length) { $('.row-main.active .read-less a').triggerHandler('click'); } else { $('.row-main.active .read-more a').triggerHandler('click'); } break; } } // Jobs page shortcuts if ($('.jobs').length) { switch (e.which) { case 13: // ENTER: go to content related to focused activity window.location = $('.jobs tr.active a:nth(0)').attr('href'); break; case 88: // X: read more/less focused activity if ($('.jobs tr.active .type-text.expanded').length) { $('.jobs tr.active .type-text .read-less a').triggerHandler('click'); } else { $('.jobs tr.active .type-text .read-more a').triggerHandler('click'); } break; } } // for files browsing if ($('.browse-files').length && $('.browse-tabs li:nth(0).active').length) { if (e.which === 13) { // enter for changelist or job window.location = $('.browse-files tbody tr.active a').attr('href'); } else if (e.which === 88) { // x for read-more if ($('.activity-stream tbody tr.active .expanded').length) { $('.activity-stream tbody tr.active .read-less a').triggerHandler('click'); } else { $('.activity-stream tbody tr.active .read-more a').triggerHandler('click'); } } } // for viewing changelist history if ($('.change-history').length && $('.browse-tabs li:nth(1).active').length) { if (e.which === 13) { // enter window.location = $('.change-history tbody tr.active td:nth(0) a:nth(0)').attr('href'); } else if (e.which === 88) { // x for read-more if ($('.change-history tbody tr.active .expanded').length) { $('.change-history tbody tr.active .read-less a').triggerHandler('click'); } else { $('.change-history tbody tr.active .read-more a').triggerHandler('click'); } } } // viewing a changelist or review if ($('.change-files').length) { if (e.which === 13 || e.which === 88) { // enter if ($('.diff-wrapper.active.collapsed').length) { $('.diff-wrapper.active .diff-details').collapse('show'); } else { $('.diff-wrapper.active .diff-details').collapse('hide'); } } } // for viewing a reviews queue if ($('.reviews-table').length) { if (e.which === 13) { // enter window.location = $('.reviews-table tbody tr.active td:nth(0) a:nth(0)').attr('href'); } else if (e.which === 88) { // x for read-more if ($('.reviews-table tbody tr.active .expanded').length) { $('.reviews-table tbody tr.active .read-less a').triggerHandler('click'); } else { $('.reviews-table tbody tr.active .read-more a').triggerHandler('click'); } } } // Make the row at 'index' the active, highlighted one if (rowFocused) { if ($('.browse-files' && $('.browse-tabs li:nth(0).active').length).length) { var focusedActivity = $('.browse-files tbody tr:nth(' + index + ')'); var activeActivity = $('.browse-files tbody tr.active'); } else if ($('.change-files').length) { var focusedActivity = $('.diff-wrapper:nth(' + index + ')'); var activeActivity = $('.diff-wrapper.active'); } else if ($('.activity-stream').length) { var focusedActivity = $('.row-main:nth(' + index + ')'); var activeActivity = $('.row-main.active'); $('.row-append td.active').removeClass('active'); $('.row-append:nth(' + index + ') td').addClass('active'); $('.row-main.active td.active').removeClass('active'); $('.row-main:nth(' + index + ') td:nth(0)').addClass('active'); } else if ($('.change-history' && $('.browse-tabs li:nth(1).active').length).length) { var focusedActivity = $('.change-history tbody tr:nth(' + index + ')'); var activeActivity = $('.change-history tbody tr.active'); } else if ($('.reviews-table').length) { var focusedActivity = $('tr[data-id]:nth(' + index + ')'); var activeActivity = $('tr.active'); } else if ($('.jobs').length) { var focusedActivity = $('.jobs tr:nth(' + (index+1) + ')'); var activeActivity = $('.jobs tr.active'); } activeActivity.removeClass('active'); focusedActivity.addClass('active'); if (focusedActivity.length) { $('html, body').animate({ scrollTop: focusedActivity.offset().top - 300 }, 0); } e.preventDefault(); } });
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 8484 | Allan Yu |
Fixed bugs: * Styling of hotkey help dialog (open with '?') no longer messes with other modal dialogs in Swarm * Key presses won't override key presses when focusing on a text box. * Fixed styling of highlighted rows New features: * Use J/K to cycle through files in a changelist or review. Use ENTER or X to expand/collapse the file * Use '5' to jump to 'Jobs' * Updated hotkey help dialog (open with '?') |
||
#1 | 8400 | Matt Attaway |
Add the 'Bee Keys' Swarm extension This extension adds hotkeys to navigate the Swarm interface. Once installed press '?' for details. |