Commit 39ff420b authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ee-ph-shortcut-js-modules' into 'master'

EE version of ph-shortcut-js-modules

See merge request gitlab-org/gitlab-ee!3148
parents 8df74d55 b76e971b
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
/* global ProjectSelect */
/* global ShortcutsNavigation */
/* global IssuableIndex */
/* global ShortcutsIssuable */
/* global Milestone */
/* global IssuableForm */
/* global LabelsSelect */
......@@ -32,13 +30,9 @@ import CILintEditor from './ci_lint_editor';
/* global ProjectImport */
import Labels from './labels';
import LabelManager from './label_manager';
/* global Shortcuts */
/* global ShortcutsFindFile */
/* global Sidebar */
/* global WeightSelect */
/* global AdminEmailSelect */
/* global ShortcutsWiki */
import CommitsList from './commits';
import Issue from './issue';
import BindInOut from './behaviors/bind_in_out';
......@@ -84,6 +78,10 @@ import initChangesDropdown from './init_changes_dropdown';
import AbuseReports from './abuse_reports';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
import AjaxLoadingSpinner from './ajax_loading_spinner';
import Shortcuts from './shortcuts';
import ShortcutsNavigation from './shortcuts_navigation';
import ShortcutsFindFile from './shortcuts_find_file';
import ShortcutsIssuable from './shortcuts_issuable';
import U2FAuthenticate from './u2f/authenticate';
// EE-only
......
......@@ -21,15 +21,6 @@ window._ = _;
window.Dropzone = Dropzone;
window.Sortable = Sortable;
// shortcuts
import './shortcuts';
import './shortcuts_blob';
import './shortcuts_dashboard_navigation';
import './shortcuts_navigation';
import './shortcuts_find_file';
import './shortcuts_issuable';
import './shortcuts_network';
// templates
import './templates/issuable_template_selector';
import './templates/issuable_template_selectors';
......
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, quotes, no-var, vars-on-top, camelcase, comma-dangle, consistent-return, max-len */
/* global ShortcutsNetwork */
import ShortcutsNetwork from '../shortcuts_network';
import Network from './network';
$(function() {
......
/* 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 */
import Cookies from 'js-cookie';
import Mousetrap from 'mousetrap';
import findAndFollowLink from './shortcuts_dashboard_navigation';
(function() {
this.Shortcuts = (function() {
function Shortcuts(skipResetBindings) {
const defaultStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (e, element, combo) => {
if (['ctrl+shift+p', 'command+shift+p'].indexOf(combo) !== -1) {
return false;
}
return defaultStopCallback(e, element, combo);
};
export default class Shortcuts {
constructor(skipResetBindings) {
this.onToggleHelp = this.onToggleHelp.bind(this);
this.enabledHelp = [];
if (!skipResetBindings) {
......@@ -15,8 +20,8 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
}
Mousetrap.bind('?', this.onToggleHelp);
Mousetrap.bind('s', Shortcuts.focusSearch);
Mousetrap.bind('f', (e => this.focusFilter(e)));
Mousetrap.bind('p b', this.onTogglePerfBar);
Mousetrap.bind('f', this.focusFilter.bind(this));
Mousetrap.bind('p b', Shortcuts.onTogglePerfBar);
const findFileURL = document.body.dataset.findFile;
......@@ -29,20 +34,27 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
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() {
return gl.utils.visitUrl(findFileURL);
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], Shortcuts.toggleMarkdownPreview);
if (typeof findFileURL !== 'undefined' && findFileURL !== null) {
Mousetrap.bind('t', () => {
gl.utils.visitUrl(findFileURL);
});
}
$(document).on('click.more_help', '.js-more-help-button', function clickMoreHelp(e) {
$(this).remove();
$('.hidden-shortcut').show();
e.preventDefault();
});
}
Shortcuts.prototype.onToggleHelp = function(e) {
onToggleHelp(e) {
e.preventDefault();
return Shortcuts.toggleHelp(this.enabledHelp);
};
Shortcuts.toggleHelp(this.enabledHelp);
}
Shortcuts.prototype.onTogglePerfBar = function(e) {
static onTogglePerfBar(e) {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
if (Cookies.get(performanceBarCookieName) === 'true') {
......@@ -51,9 +63,9 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
Cookies.set(performanceBarCookieName, 'true', { path: '/' });
}
gl.utils.refreshCurrentPage();
};
}
Shortcuts.prototype.toggleMarkdownPreview = function(e) {
static toggleMarkdownPreview(e) {
// Check if short-cut was triggered while in Write Mode
const $target = $(e.target);
const $form = $target.closest('form');
......@@ -61,68 +73,44 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
if ($target.hasClass('js-note-text')) {
$('.js-md-preview-button', $form).focus();
}
return $(document).triggerHandler('markdown-preview:toggle', [e]);
};
$(document).triggerHandler('markdown-preview:toggle', [e]);
}
static toggleHelp(location) {
const $modal = $('#modal-shortcuts');
Shortcuts.toggleHelp = function(location) {
var $modal;
$modal = $('#modal-shortcuts');
if ($modal.length) {
$modal.modal('toggle');
return;
}
return $.ajax({
$.ajax({
url: gon.shortcuts_path,
dataType: 'script',
success: function(e) {
var i, l, len, results;
success() {
if (location && location.length > 0) {
results = [];
for (i = 0, len = location.length; i < len; i += 1) {
l = location[i];
results.push($(l).show());
const results = [];
for (let i = 0, len = location.length; i < len; i += 1) {
results.push($(location[i]).show());
}
return results;
} else {
}
$('.hidden-shortcut').show();
return $('.js-more-help-button').remove();
}
}
},
});
};
}
Shortcuts.prototype.focusFilter = function(e) {
if (this.filterInput == null) {
focusFilter(e) {
if (!this.filterInput) {
this.filterInput = $('input[type=search]', '.nav-controls');
}
this.filterInput.focus();
return e.preventDefault();
};
e.preventDefault();
}
Shortcuts.focusSearch = function(e) {
static focusSearch(e) {
$('#search').focus();
return e.preventDefault();
};
return Shortcuts;
})();
$(document).on('click.more_help', '.js-more-help-button', function(e) {
$(this).remove();
$('.hidden-shortcut').show();
return e.preventDefault();
});
Mousetrap.stopCallback = (function() {
var defaultStopCallback;
defaultStopCallback = Mousetrap.stopCallback;
return function(e, element, combo) {
// allowed shortcuts if textarea, input, contenteditable are focused
if (['ctrl+shift+p', 'command+shift+p'].indexOf(combo) !== -1) {
return false;
} else {
return defaultStopCallback.apply(this, arguments);
e.preventDefault();
}
};
})();
}).call(window);
}
/* global Mousetrap */
/* global Shortcuts */
import './shortcuts';
import Shortcuts from './shortcuts';
const defaults = {
skipResetBindings: false,
......
/* 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 */
/* global Mousetrap */
/* global ShortcutsNavigation */
import './shortcuts_navigation';
import ShortcutsNavigation from './shortcuts_navigation';
(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;
export default class ShortcutsFindFile extends ShortcutsNavigation {
constructor(projectFindFile) {
super();
this.ShortcutsFindFile = (function(superClass) {
extend(ShortcutsFindFile, superClass);
function ShortcutsFindFile(projectFindFile) {
var _oldStopCallback;
const oldStopCallback = Mousetrap.stopCallback;
this.projectFindFile = projectFindFile;
ShortcutsFindFile.__super__.constructor.call(this);
_oldStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (function(_this) {
// override to fire shortcuts action when focus in textbox
return function(event, element, combo) {
if (element === _this.projectFindFile.inputElement[0] && (combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter')) {
Mousetrap.stopCallback = (e, element, combo) => {
if (
element === this.projectFindFile.inputElement[0] &&
(combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter')
) {
// when press up/down key in textbox, cusor prevent to move to home/end
event.preventDefault();
return false;
}
return _oldStopCallback(event, element, combo);
return oldStopCallback(e, element, combo);
};
})(this);
Mousetrap.bind('up', this.projectFindFile.selectRowUp);
Mousetrap.bind('down', this.projectFindFile.selectRowDown);
Mousetrap.bind('esc', this.projectFindFile.goToTree);
Mousetrap.bind('enter', this.projectFindFile.goToBlob);
}
return ShortcutsFindFile;
})(ShortcutsNavigation);
}).call(window);
}
/* 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, one-var-declaration-per-line, quotes, prefer-arrow-callback, consistent-return, prefer-template, no-mixed-operators */
/* global Mousetrap */
/* global ShortcutsNavigation */
/* global sidebar */
import _ from 'underscore';
import 'mousetrap';
import './shortcuts_navigation';
(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.ShortcutsIssuable = (function(superClass) {
extend(ShortcutsIssuable, superClass);
function ShortcutsIssuable(isMergeRequest) {
ShortcutsIssuable.__super__.constructor.call(this);
Mousetrap.bind('a', this.openSidebarDropdown.bind(this, 'assignee'));
Mousetrap.bind('m', this.openSidebarDropdown.bind(this, 'milestone'));
Mousetrap.bind('r', (function(_this) {
return function() {
_this.replyWithSelectedText(isMergeRequest);
return false;
};
})(this));
Mousetrap.bind('e', (function(_this) {
return function() {
_this.editIssue();
return false;
};
})(this));
Mousetrap.bind('l', this.openSidebarDropdown.bind(this, 'labels'));
import ShortcutsNavigation from './shortcuts_navigation';
export default class ShortcutsIssuable extends ShortcutsNavigation {
constructor(isMergeRequest) {
super();
this.$replyField = isMergeRequest ? $('.js-main-target-form #note_note') : $('.js-main-target-form .js-vue-comment-form');
this.editBtn = document.querySelector('.issuable-edit');
Mousetrap.bind('a', () => ShortcutsIssuable.openSidebarDropdown('assignee'));
Mousetrap.bind('m', () => ShortcutsIssuable.openSidebarDropdown('milestone'));
Mousetrap.bind('l', () => ShortcutsIssuable.openSidebarDropdown('labels'));
Mousetrap.bind('r', this.replyWithSelectedText.bind(this));
Mousetrap.bind('e', this.editIssue.bind(this));
if (isMergeRequest) {
this.enabledHelp.push('.hidden-shortcut.merge_requests');
} else {
......@@ -38,63 +25,50 @@ import './shortcuts_navigation';
}
}
ShortcutsIssuable.prototype.replyWithSelectedText = function(isMergeRequest) {
var quote, documentFragment, el, selected, separator;
let replyField;
replyWithSelectedText() {
const documentFragment = window.gl.utils.getSelectedFragment();
if (isMergeRequest) {
replyField = $('.js-main-target-form #note_note');
} else {
replyField = $('.js-main-target-form .js-vue-comment-form');
}
documentFragment = window.gl.utils.getSelectedFragment();
if (!documentFragment) {
replyField.focus();
return;
this.$replyField.focus();
return false;
}
el = window.gl.CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true));
selected = window.gl.CopyAsGFM.nodeToGFM(el);
const el = window.gl.CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true));
const selected = window.gl.CopyAsGFM.nodeToGFM(el);
if (selected.trim() === "") {
return;
if (selected.trim() === '') {
return false;
}
quote = _.map(selected.split("\n"), function(val) {
return ("> " + val).trim() + "\n";
});
// If replyField already has some content, add a newline before our quote
separator = replyField.val().trim() !== "" && "\n\n" || '';
replyField.val(function(a, current) {
return current + separator + quote.join('') + "\n";
});
const quote = _.map(selected.split('\n'), val => `${(`> ${val}`).trim()}\n`);
// Trigger autosave
replyField.trigger('input').trigger('change');
// If replyField already has some content, add a newline before our quote
const separator = (this.$replyField.val().trim() !== '' && '\n\n') || '';
this.$replyField.val((a, current) => `${current}${separator}${quote.join('')}\n`)
.trigger('input')
.trigger('change');
// Trigger autosize
var event = document.createEvent('Event');
const event = document.createEvent('Event');
event.initEvent('autosize:update', true, false);
replyField.get(0).dispatchEvent(event);
this.$replyField.get(0).dispatchEvent(event);
// Focus the input field
return replyField.focus();
};
this.$replyField.focus();
return false;
}
ShortcutsIssuable.prototype.editIssue = function() {
var $editBtn;
$editBtn = $('.issuable-edit');
editIssue() {
// Need to click the element as on issues, editing is inline
// on merge request, editing is on a different page
$editBtn.get(0).click();
};
this.editBtn.click();
ShortcutsIssuable.prototype.openSidebarDropdown = function(name) {
sidebar.openDropdown(name);
return false;
};
}
return ShortcutsIssuable;
})(ShortcutsNavigation);
}).call(window);
static openSidebarDropdown(name) {
sidebar.openDropdown(name);
return false;
}
}
/* 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';
import './shortcuts';
import Shortcuts from './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;
export default class ShortcutsNavigation extends Shortcuts {
constructor() {
super();
this.ShortcutsNavigation = (function(superClass) {
extend(ShortcutsNavigation, superClass);
function ShortcutsNavigation() {
ShortcutsNavigation.__super__.constructor.call(this);
Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project'));
Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-project-activity'));
Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree'));
......@@ -28,9 +21,7 @@ import './shortcuts';
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');
}
return ShortcutsNavigation;
})(Shortcuts);
}).call(window);
}
/* 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, max-len */
/* global Mousetrap */
/* global ShortcutsNavigation */
import ShortcutsNavigation from './shortcuts_navigation';
import './shortcuts_navigation';
export default class ShortcutsNetwork extends ShortcutsNavigation {
constructor(graph) {
super();
(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;
Mousetrap.bind(['left', 'h'], graph.scrollLeft);
Mousetrap.bind(['right', 'l'], graph.scrollRight);
Mousetrap.bind(['up', 'k'], graph.scrollUp);
Mousetrap.bind(['down', 'j'], graph.scrollDown);
Mousetrap.bind(['shift+up', 'shift+k'], graph.scrollTop);
Mousetrap.bind(['shift+down', 'shift+j'], graph.scrollBottom);
this.ShortcutsNetwork = (function(superClass) {
extend(ShortcutsNetwork, superClass);
function ShortcutsNetwork(graph) {
this.graph = graph;
ShortcutsNetwork.__super__.constructor.call(this);
Mousetrap.bind(['left', 'h'], this.graph.scrollLeft);
Mousetrap.bind(['right', 'l'], this.graph.scrollRight);
Mousetrap.bind(['up', 'k'], this.graph.scrollUp);
Mousetrap.bind(['down', 'j'], this.graph.scrollDown);
Mousetrap.bind(['shift+up', 'shift+k'], this.graph.scrollTop);
Mousetrap.bind(['shift+down', 'shift+j'], this.graph.scrollBottom);
this.enabledHelp.push('.hidden-shortcut.network');
}
return ShortcutsNetwork;
})(ShortcutsNavigation);
}).call(window);
}
/* eslint-disable class-methods-use-this */
/* global Mousetrap */
/* global ShortcutsNavigation */
import ShortcutsNavigation from './shortcuts_navigation';
import findAndFollowLink from './shortcuts_dashboard_navigation';
export default class ShortcutsWiki extends ShortcutsNavigation {
......
/* global ShortcutsIssuable */
import '~/copy_as_gfm';
import '~/shortcuts_issuable';
import ShortcutsIssuable from '~/shortcuts_issuable';
describe('ShortcutsIssuable', () => {
const fixtureName = 'merge_requests/diff_comment.html.raw';
......
/* global Shortcuts */
import Shortcuts from '~/shortcuts';
describe('Shortcuts', () => {
const fixtureName = 'merge_requests/diff_comment.html.raw';
const createEvent = (type, target) => $.Event(type, {
......@@ -8,19 +9,17 @@ describe('Shortcuts', () => {
preloadFixtures(fixtureName);
describe('toggleMarkdownPreview', () => {
let sc;
beforeEach(() => {
loadFixtures(fixtureName);
spyOnEvent('.js-new-note-form .js-md-preview-button', 'focus');
spyOnEvent('.edit-note .js-md-preview-button', 'focus');
sc = new Shortcuts();
new Shortcuts(); // eslint-disable-line no-new
});
it('focuses preview button in form', () => {
sc.toggleMarkdownPreview(
Shortcuts.toggleMarkdownPreview(
createEvent('KeyboardEvent', document.querySelector('.js-new-note-form .js-note-text'),
));
......@@ -31,7 +30,7 @@ describe('Shortcuts', () => {
document.querySelector('.js-note-edit').click();
setTimeout(() => {
sc.toggleMarkdownPreview(
Shortcuts.toggleMarkdownPreview(
createEvent('KeyboardEvent', document.querySelector('.edit-note .js-note-text'),
));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment