Merge branch 'menu-shortcut' into 'master'
Add keyboard shortcuts to main menu. Closes #30036 See merge request !10243
This commit is contained in:
commit
496208c9bd
|
@ -24,7 +24,6 @@
|
|||
/* global Search */
|
||||
/* global Admin */
|
||||
/* global NamespaceSelects */
|
||||
/* global ShortcutsDashboardNavigation */
|
||||
/* global Project */
|
||||
/* global ProjectAvatar */
|
||||
/* global CompareAutocomplete */
|
||||
|
@ -378,7 +377,6 @@ const ShortcutsBlob = require('./shortcuts_blob');
|
|||
break;
|
||||
case 'dashboard':
|
||||
case 'root':
|
||||
shortcut_handler = new ShortcutsDashboardNavigation();
|
||||
new UserCallout();
|
||||
break;
|
||||
case 'groups':
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
|
||||
/* global Mousetrap */
|
||||
/* global findFileURL */
|
||||
import findAndFollowLink from './shortcuts_dashboard_navigation';
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
@ -14,11 +15,33 @@
|
|||
}
|
||||
Mousetrap.bind('?', this.onToggleHelp);
|
||||
Mousetrap.bind('s', Shortcuts.focusSearch);
|
||||
Mousetrap.bind('f', (function(_this) {
|
||||
return function(e) {
|
||||
return _this.focusFilter(e);
|
||||
};
|
||||
})(this));
|
||||
Mousetrap.bind('f', (e => this.focusFilter(e)));
|
||||
|
||||
const $globalDropdownMenu = $('.global-dropdown-menu');
|
||||
const $globalDropdownToggle = $('.global-dropdown-toggle');
|
||||
|
||||
$('.global-dropdown').on('hide.bs.dropdown', () => {
|
||||
$globalDropdownMenu.removeClass('shortcuts');
|
||||
});
|
||||
|
||||
Mousetrap.bind('n', () => {
|
||||
$globalDropdownMenu.toggleClass('shortcuts');
|
||||
$globalDropdownToggle.trigger('click');
|
||||
|
||||
if (!$globalDropdownMenu.is(':visible')) {
|
||||
$globalDropdownToggle.blur();
|
||||
}
|
||||
});
|
||||
|
||||
Mousetrap.bind('shift+t', () => findAndFollowLink('.shortcuts-todos'));
|
||||
Mousetrap.bind('shift+a', () => findAndFollowLink('.dashboard-shortcuts-activity'));
|
||||
Mousetrap.bind('shift+i', () => findAndFollowLink('.dashboard-shortcuts-issues'));
|
||||
Mousetrap.bind('shift+m', () => findAndFollowLink('.dashboard-shortcuts-merge_requests'));
|
||||
Mousetrap.bind('shift+p', () => findAndFollowLink('.dashboard-shortcuts-projects'));
|
||||
Mousetrap.bind('shift+g', () => findAndFollowLink('.dashboard-shortcuts-groups'));
|
||||
Mousetrap.bind('shift+l', () => findAndFollowLink('.dashboard-shortcuts-milestones'));
|
||||
Mousetrap.bind('shift+s', () => findAndFollowLink('.dashboard-shortcuts-snippets'));
|
||||
|
||||
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], this.toggleMarkdownPreview);
|
||||
if (typeof findFileURL !== "undefined" && findFileURL !== null) {
|
||||
Mousetrap.bind('t', function() {
|
||||
|
|
|
@ -1,43 +1,12 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign */
|
||||
/* global Mousetrap */
|
||||
/* global Shortcuts */
|
||||
/**
|
||||
* Helper function that finds the href of the fiven selector and updates the location.
|
||||
*
|
||||
* @param {String} selector
|
||||
*/
|
||||
export default (selector) => {
|
||||
const link = document.querySelector(selector).getAttribute('href');
|
||||
|
||||
require('./shortcuts');
|
||||
|
||||
(function() {
|
||||
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
hasProp = {}.hasOwnProperty;
|
||||
|
||||
this.ShortcutsDashboardNavigation = (function(superClass) {
|
||||
extend(ShortcutsDashboardNavigation, superClass);
|
||||
|
||||
function ShortcutsDashboardNavigation() {
|
||||
ShortcutsDashboardNavigation.__super__.constructor.call(this);
|
||||
Mousetrap.bind('g a', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-activity');
|
||||
});
|
||||
Mousetrap.bind('g i', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-issues');
|
||||
});
|
||||
Mousetrap.bind('g m', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-merge_requests');
|
||||
});
|
||||
Mousetrap.bind('g t', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-todos');
|
||||
});
|
||||
Mousetrap.bind('g p', function() {
|
||||
return ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-projects');
|
||||
});
|
||||
}
|
||||
|
||||
ShortcutsDashboardNavigation.findAndFollowLink = function(selector) {
|
||||
var link;
|
||||
link = $(selector).attr('href');
|
||||
if (link) {
|
||||
return window.location = link;
|
||||
}
|
||||
};
|
||||
|
||||
return ShortcutsDashboardNavigation;
|
||||
})(Shortcuts);
|
||||
}).call(window);
|
||||
if (link) {
|
||||
window.location = link;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign */
|
||||
/* global Mousetrap */
|
||||
/* global Shortcuts */
|
||||
import findAndFollowLink from './shortcuts_dashboard_navigation';
|
||||
|
||||
require('./shortcuts');
|
||||
|
||||
|
@ -13,59 +14,23 @@ require('./shortcuts');
|
|||
|
||||
function ShortcutsNavigation() {
|
||||
ShortcutsNavigation.__super__.constructor.call(this);
|
||||
Mousetrap.bind('g p', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-project');
|
||||
});
|
||||
Mousetrap.bind('g e', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-project-activity');
|
||||
});
|
||||
Mousetrap.bind('g f', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-tree');
|
||||
});
|
||||
Mousetrap.bind('g c', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-commits');
|
||||
});
|
||||
Mousetrap.bind('g b', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-builds');
|
||||
});
|
||||
Mousetrap.bind('g n', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-network');
|
||||
});
|
||||
Mousetrap.bind('g g', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-repository-charts');
|
||||
});
|
||||
Mousetrap.bind('g i', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues');
|
||||
});
|
||||
Mousetrap.bind('g l', function() {
|
||||
ShortcutsNavigation.findAndFollowLink('.shortcuts-issue-boards');
|
||||
});
|
||||
Mousetrap.bind('g m', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests');
|
||||
});
|
||||
Mousetrap.bind('g t', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-todos');
|
||||
});
|
||||
Mousetrap.bind('g w', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-wiki');
|
||||
});
|
||||
Mousetrap.bind('g s', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-snippets');
|
||||
});
|
||||
Mousetrap.bind('i', function() {
|
||||
return ShortcutsNavigation.findAndFollowLink('.shortcuts-new-issue');
|
||||
});
|
||||
Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project'));
|
||||
Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-project-activity'));
|
||||
Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree'));
|
||||
Mousetrap.bind('g c', () => findAndFollowLink('.shortcuts-commits'));
|
||||
Mousetrap.bind('g j', () => findAndFollowLink('.shortcuts-builds'));
|
||||
Mousetrap.bind('g n', () => findAndFollowLink('.shortcuts-network'));
|
||||
Mousetrap.bind('g d', () => findAndFollowLink('.shortcuts-repository-charts'));
|
||||
Mousetrap.bind('g i', () => findAndFollowLink('.shortcuts-issues'));
|
||||
Mousetrap.bind('g b', () => findAndFollowLink('.shortcuts-issue-boards'));
|
||||
Mousetrap.bind('g m', () => findAndFollowLink('.shortcuts-merge_requests'));
|
||||
Mousetrap.bind('g t', () => findAndFollowLink('.shortcuts-todos'));
|
||||
Mousetrap.bind('g w', () => findAndFollowLink('.shortcuts-wiki'));
|
||||
Mousetrap.bind('g s', () => findAndFollowLink('.shortcuts-snippets'));
|
||||
Mousetrap.bind('i', () => findAndFollowLink('.shortcuts-new-issue'));
|
||||
this.enabledHelp.push('.hidden-shortcut.project');
|
||||
}
|
||||
|
||||
ShortcutsNavigation.findAndFollowLink = function(selector) {
|
||||
var link;
|
||||
link = $(selector).attr('href');
|
||||
if (link) {
|
||||
return window.location = link;
|
||||
}
|
||||
};
|
||||
|
||||
return ShortcutsNavigation;
|
||||
})(Shortcuts);
|
||||
}).call(window);
|
||||
|
|
|
@ -187,6 +187,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
.shortcut-mappings {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.shortcuts .shortcut-mappings {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
%tr
|
||||
%th
|
||||
%th Global Shortcuts
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key n
|
||||
%td Main Navigation
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key s
|
||||
|
@ -39,24 +43,46 @@
|
|||
.key
|
||||
%i.fa.fa-arrow-up
|
||||
%td Edit last comment (when focused on an empty textarea)
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project Files browsing
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-up
|
||||
%td Move selection up
|
||||
.key shift t
|
||||
%td
|
||||
Go to todos
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-down
|
||||
%td Move selection down
|
||||
.key shift a
|
||||
%td
|
||||
Go to the activity feed
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key enter
|
||||
%td Open Selection
|
||||
.key shift p
|
||||
%td
|
||||
Go to projects
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift i
|
||||
%td
|
||||
Go to issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift m
|
||||
%td
|
||||
Go to merge requests
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift g
|
||||
%td
|
||||
Go to groups
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift l
|
||||
%td
|
||||
Go to milestones
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key shift s
|
||||
%td
|
||||
Go to snippets
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
|
@ -79,51 +105,8 @@
|
|||
%td.shortcut
|
||||
.key esc
|
||||
%td Go back
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project File
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key y
|
||||
%td Go to file permalink
|
||||
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody.hidden-shortcut.project{ style: 'display:none' }
|
||||
%tr
|
||||
%th
|
||||
%th Global Dashboard
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key a
|
||||
%td
|
||||
Go to the activity feed
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key p
|
||||
%td
|
||||
Go to projects
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key i
|
||||
%td
|
||||
Go to issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key m
|
||||
%td
|
||||
Go to merge requests
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key t
|
||||
%td
|
||||
Go to todos
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
|
@ -155,7 +138,7 @@
|
|||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key b
|
||||
.key j
|
||||
%td
|
||||
Go to jobs
|
||||
%tr
|
||||
|
@ -167,7 +150,7 @@
|
|||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key g
|
||||
.key d
|
||||
%td
|
||||
Go to repository charts
|
||||
%tr
|
||||
|
@ -179,7 +162,7 @@
|
|||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key l
|
||||
.key b
|
||||
%td
|
||||
Go to issue boards
|
||||
%tr
|
||||
|
@ -194,6 +177,12 @@
|
|||
.key s
|
||||
%td
|
||||
Go to snippets
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key w
|
||||
%td
|
||||
Go to wiki
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key t
|
||||
|
@ -202,6 +191,33 @@
|
|||
%td.shortcut
|
||||
.key i
|
||||
%td New issue
|
||||
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project Files browsing
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-up
|
||||
%td Move selection up
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.fa.fa-arrow-down
|
||||
%td Move selection down
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key enter
|
||||
%td Open Selection
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project File
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key y
|
||||
%td Go to file permalink
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody.hidden-shortcut.network{ style: 'display:none' }
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
%ul
|
||||
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
|
||||
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
P
|
||||
%span
|
||||
Projects
|
||||
= nav_link(path: 'dashboard#activity') do
|
||||
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
A
|
||||
%span
|
||||
Activity
|
||||
- if koding_enabled?
|
||||
|
@ -13,25 +21,45 @@
|
|||
%span
|
||||
Koding
|
||||
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
|
||||
= link_to dashboard_groups_path, title: 'Groups' do
|
||||
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
G
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: 'dashboard/milestones') do
|
||||
= link_to dashboard_milestones_path, title: 'Milestones' do
|
||||
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
L
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'dashboard#issues') do
|
||||
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
I
|
||||
%span
|
||||
Issues
|
||||
.badge= number_with_delimiter(cached_assigned_issuables_count(current_user, :issues, :opened))
|
||||
= nav_link(path: 'dashboard#merge_requests') do
|
||||
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
M
|
||||
%span
|
||||
Merge Requests
|
||||
.badge= number_with_delimiter(cached_assigned_issuables_count(current_user, :merge_requests, :opened))
|
||||
= nav_link(controller: 'dashboard/snippets') do
|
||||
= link_to dashboard_snippets_path, title: 'Snippets' do
|
||||
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
|
||||
.shortcut-mappings
|
||||
.key
|
||||
= icon('arrow-up', 'aria-label' => 'hidden')
|
||||
S
|
||||
%span
|
||||
Snippets
|
||||
%li.divider
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Add keyboard shortcuts to main menu
|
||||
merge_request:
|
||||
author:
|
|
@ -26,7 +26,7 @@ Feature: Project Shortcuts
|
|||
|
||||
@javascript
|
||||
Scenario: Navigate to repository charts tab
|
||||
Given I press "g" and "g"
|
||||
Given I press "g" and "d"
|
||||
Then the active sub tab should be Charts
|
||||
And the active main tab should be Repository
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ class Spinach::Features::ProjectShortcuts < Spinach::FeatureSteps
|
|||
find('body').native.send_key('n')
|
||||
end
|
||||
|
||||
step 'I press "g" and "g"' do
|
||||
find('body').native.send_key('g')
|
||||
step 'I press "g" and "d"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('d')
|
||||
end
|
||||
|
||||
step 'I press "g" and "s"' do
|
||||
|
|
|
@ -14,7 +14,7 @@ describe 'Issue Boards shortcut', feature: true, js: true do
|
|||
end
|
||||
|
||||
it 'takes user to issue board index' do
|
||||
find('body').native.send_keys('gl')
|
||||
find('body').native.send_keys('gb')
|
||||
expect(page).to have_selector('.boards-list')
|
||||
|
||||
wait_for_vue_resource
|
||||
|
|
|
@ -3,27 +3,23 @@ require 'spec_helper'
|
|||
feature 'Dashboard shortcuts', feature: true, js: true do
|
||||
before do
|
||||
login_as :user
|
||||
visit dashboard_projects_path
|
||||
visit root_dashboard_path
|
||||
end
|
||||
|
||||
scenario 'Navigate to tabs' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('p')
|
||||
find('body').native.send_keys([:shift, 'P'])
|
||||
|
||||
check_page_title('Projects')
|
||||
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('i')
|
||||
find('body').native.send_key([:shift, 'I'])
|
||||
|
||||
check_page_title('Issues')
|
||||
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('m')
|
||||
find('body').native.send_key([:shift, 'M'])
|
||||
|
||||
check_page_title('Merge Requests')
|
||||
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('t')
|
||||
find('body').native.send_keys([:shift, 'T'])
|
||||
|
||||
check_page_title('Todos')
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue