Browse Source

Make Ctrl+Enter (quick submit) work for issue comment and wiki editor (#19729)

* Make Ctrl+Enter (quick submit) work for issue comment and wiki editor

* Remove the required `SubmitReviewForm.Type`, empty type (triggered by quick submit) means "comment"

* Merge duplicate code
tags/v1.18.0-dev
wxiaoguang 2 years ago
parent
commit
cc7236e852
No account linked to committer's email address

+ 4
- 2
services/forms/repo_form.go View File

// SubmitReviewForm for submitting a finished code review // SubmitReviewForm for submitting a finished code review
type SubmitReviewForm struct { type SubmitReviewForm struct {
Content string Content string
Type string `binding:"Required;In(approve,comment,reject)"`
Type string
CommitID string CommitID string
Files []string Files []string
} }
return middleware.Validate(errs, ctx.Data, f, ctx.Locale) return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
} }


// ReviewType will return the corresponding reviewtype for type
// ReviewType will return the corresponding ReviewType for type
func (f SubmitReviewForm) ReviewType() models.ReviewType { func (f SubmitReviewForm) ReviewType() models.ReviewType {
switch f.Type { switch f.Type {
case "approve": case "approve":
return models.ReviewTypeComment return models.ReviewTypeComment
case "reject": case "reject":
return models.ReviewTypeReject return models.ReviewTypeReject
case "":
return models.ReviewTypeComment // default to comment when doing quick-submit (Ctrl+Enter) on the review form
default: default:
return models.ReviewTypeUnknown return models.ReviewTypeUnknown
} }

+ 1
- 1
templates/repo/diff/box.tmpl View File

<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a> <a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
</div> </div>
<div class="ui bottom attached active write tab segment"> <div class="ui bottom attached active write tab segment">
<textarea class="review-textarea" tabindex="1" name="content"></textarea>
<textarea class="review-textarea js-quick-submit" tabindex="1" name="content"></textarea>
</div> </div>
<div class="ui bottom attached tab preview segment markup"> <div class="ui bottom attached tab preview segment markup">
{{$.i18n.Tr "loading"}} {{$.i18n.Tr "loading"}}

+ 1
- 1
templates/repo/issue/view_content.tmpl View File

</div> </div>
<div class="field"> <div class="field">
<div class="ui bottom active tab write"> <div class="ui bottom active tab write">
<textarea tabindex="1" name="content"></textarea>
<textarea tabindex="1" name="content" class="js-quick-submit"></textarea>
</div> </div>
<div class="ui bottom tab preview markup"> <div class="ui bottom tab preview markup">
{{$.i18n.Tr "loading"}} {{$.i18n.Tr "loading"}}

+ 2
- 2
templates/user/settings/keys_ssh.tmpl View File

</div> </div>
<div class="field {{if .Err_Content}}error{{end}}"> <div class="field {{if .Err_Content}}error{{end}}">
<label for="content">{{.i18n.Tr "settings.key_content"}}</label> <label for="content">{{.i18n.Tr "settings.key_content"}}</label>
<textarea id="ssh-key-content" name="content" placeholder="{{.i18n.Tr "settings.key_content_ssh_placeholder"}}" required>{{.content}}</textarea>
<textarea id="ssh-key-content" name="content" class="js-quick-submit" placeholder="{{.i18n.Tr "settings.key_content_ssh_placeholder"}}" required>{{.content}}</textarea>
</div> </div>
<input name="type" type="hidden" value="ssh"> <input name="type" type="hidden" value="ssh">
<button class="ui green button"> <button class="ui green button">
</div> </div>
<div class="field"> <div class="field">
<label for="signature">{{$.i18n.Tr "settings.ssh_token_signature"}}</label> <label for="signature">{{$.i18n.Tr "settings.ssh_token_signature"}}</label>
<textarea id="ssh-key-signature" name="signature" placeholder="{{$.i18n.Tr "settings.key_signature_ssh_placeholder"}}" required>{{$.signature}}</textarea>
<textarea id="ssh-key-signature" name="signature" class="js-quick-submit" placeholder="{{$.i18n.Tr "settings.key_signature_ssh_placeholder"}}" required>{{$.signature}}</textarea>
</div> </div>
<input name="type" type="hidden" value="verify_ssh"> <input name="type" type="hidden" value="verify_ssh">
<button class="ui green button"> <button class="ui green button">

+ 18
- 3
web_src/js/features/common-global.js View File





export function initGlobalEnterQuickSubmit() { export function initGlobalEnterQuickSubmit() {
$('.js-quick-submit').on('keydown', function (e) {
if (((e.ctrlKey && !e.altKey) || e.metaKey) && (e.keyCode === 13 || e.keyCode === 10)) {
$(this).closest('form').trigger('submit');
$(document).on('keydown', '.js-quick-submit', (e) => {
if (((e.ctrlKey && !e.altKey) || e.metaKey) && (e.key === 'Enter')) {
handleGlobalEnterQuickSubmit(e.target);
return false;
} }
}); });
} }


export function handleGlobalEnterQuickSubmit(target) {
const $target = $(target);
const $form = $(target).closest('form');
if ($form.length) {
// here use the event to trigger the submit event (instead of calling `submit()` method directly)
// otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog
$form.trigger('submit');
} else {
// if no form, then the editor is for an AJAX request, dispatch an event to the target, let the target's event handler to do the AJAX request.
// the 'ce-' prefix means this is a CustomEvent
$target.trigger('ce-quick-submit');
}
}

export function initGlobalButtonClickOnEnter() { export function initGlobalButtonClickOnEnter() {
$(document).on('keypress', '.ui.button', (e) => { $(document).on('keypress', '.ui.button', (e) => {
if (e.keyCode === 13 || e.keyCode === 32) { // enter key or space bar if (e.keyCode === 13 || e.keyCode === 32) { // enter key or space bar

+ 14
- 1
web_src/js/features/comp/EasyMDE.js View File

import $ from 'jquery'; import $ from 'jquery';
import attachTribute from '../tribute.js'; import attachTribute from '../tribute.js';
import {handleGlobalEnterQuickSubmit} from '../common-global.js';


/** /**
* @returns {EasyMDE} * @returns {EasyMDE}
title: 'Revert to simple textarea', title: 'Revert to simple textarea',
}, },
], ...easyMDEOptions}); ], ...easyMDEOptions});

const inputField = easyMDE.codemirror.getInputField(); const inputField = easyMDE.codemirror.getInputField();
inputField.classList.add('js-quick-submit');
easyMDE.codemirror.setOption('extraKeys', { easyMDE.codemirror.setOption('extraKeys', {
'Cmd-Enter': codeMirrorQuickSubmit,
'Ctrl-Enter': codeMirrorQuickSubmit,
Enter: (cm) => { Enter: (cm) => {
const tributeContainer = document.querySelector('.tribute-container'); const tributeContainer = document.querySelector('.tribute-container');
if (!tributeContainer || tributeContainer.style.display === 'none') { if (!tributeContainer || tributeContainer.style.display === 'none') {
$mdeInputField.prop('required', false); $mdeInputField.prop('required', false);
return true; return true;
} }

/**
* there is no guarantee that the CodeMirror object is inside the same form as the textarea,
* so can not call handleGlobalEnterQuickSubmit directly.
* @param {CodeMirror.EditorFromTextArea} codeMirror
*/
export function codeMirrorQuickSubmit(codeMirror) {
handleGlobalEnterQuickSubmit(codeMirror.getTextArea());
}

+ 8
- 2
web_src/js/features/repo-legacy.js View File

initEasyMDEImagePaste(easyMDE, $dropzone[0], $dropzone.find('.files')); initEasyMDEImagePaste(easyMDE, $dropzone[0], $dropzone.find('.files'));
} }


const $saveButton = $editContentZone.find('.save.button');
$textarea.on('ce-quick-submit', () => {
$saveButton.trigger('click');
});

$editContentZone.find('.cancel.button').on('click', () => { $editContentZone.find('.cancel.button').on('click', () => {
$renderContent.show(); $renderContent.show();
$editContentZone.hide(); $editContentZone.hide();
dz.emit('reload'); dz.emit('reload');
} }
}); });
$editContentZone.find('.save.button').on('click', () => {

$saveButton.on('click', () => {
$renderContent.show(); $renderContent.show();
$editContentZone.hide(); $editContentZone.hide();
const $attachments = $dropzone.find('.files').find('[name=files]').map(function () { const $attachments = $dropzone.find('.files').find('[name=files]').map(function () {
initCommentContent(); initCommentContent();
}); });
}); });
} else {
} else { // use existing form
$textarea = $segment.find('textarea'); $textarea = $segment.find('textarea');
easyMDE = getAttachedEasyMDE($textarea); easyMDE = getAttachedEasyMDE($textarea);
} }

+ 6
- 4
web_src/js/features/repo-wiki.js View File

import $ from 'jquery'; import $ from 'jquery';
import {initMarkupContent} from '../markup/content.js'; import {initMarkupContent} from '../markup/content.js';
import {attachEasyMDEToElements, importEasyMDE, validateTextareaNonEmpty} from './comp/EasyMDE.js';
import {attachEasyMDEToElements, codeMirrorQuickSubmit, importEasyMDE, validateTextareaNonEmpty} from './comp/EasyMDE.js';
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';


const {csrfToken} = window.config; const {csrfToken} = window.config;
] ]
}); });


attachEasyMDEToElements(easyMDE);
easyMDE.codemirror.setOption('extraKeys', {
'Cmd-Enter': codeMirrorQuickSubmit,
'Ctrl-Enter': codeMirrorQuickSubmit,
});


const $mdeInputField = $(easyMDE.codemirror.getInputField());
$mdeInputField.addClass('js-quick-submit');
attachEasyMDEToElements(easyMDE);


$form.on('submit', () => { $form.on('submit', () => {
if (!validateTextareaNonEmpty($editArea)) { if (!validateTextareaNonEmpty($editArea)) {

Loading…
Cancel
Save