* 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 codetags/v1.18.0-dev
@@ -623,7 +623,7 @@ func (f *CodeCommentForm) Validate(req *http.Request, errs binding.Errors) bindi | |||
// SubmitReviewForm for submitting a finished code review | |||
type SubmitReviewForm struct { | |||
Content string | |||
Type string `binding:"Required;In(approve,comment,reject)"` | |||
Type string | |||
CommitID string | |||
Files []string | |||
} | |||
@@ -634,7 +634,7 @@ func (f *SubmitReviewForm) Validate(req *http.Request, errs binding.Errors) bind | |||
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 { | |||
switch f.Type { | |||
case "approve": | |||
@@ -643,6 +643,8 @@ func (f SubmitReviewForm) ReviewType() models.ReviewType { | |||
return models.ReviewTypeComment | |||
case "reject": | |||
return models.ReviewTypeReject | |||
case "": | |||
return models.ReviewTypeComment // default to comment when doing quick-submit (Ctrl+Enter) on the review form | |||
default: | |||
return models.ReviewTypeUnknown | |||
} |
@@ -180,7 +180,7 @@ | |||
<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a> | |||
</div> | |||
<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 class="ui bottom attached tab preview segment markup"> | |||
{{$.i18n.Tr "loading"}} |
@@ -202,7 +202,7 @@ | |||
</div> | |||
<div class="field"> | |||
<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 class="ui bottom tab preview markup"> | |||
{{$.i18n.Tr "loading"}} |
@@ -20,7 +20,7 @@ | |||
</div> | |||
<div class="field {{if .Err_Content}}error{{end}}"> | |||
<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> | |||
<input name="type" type="hidden" value="ssh"> | |||
<button class="ui green button"> | |||
@@ -81,7 +81,7 @@ | |||
</div> | |||
<div class="field"> | |||
<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> | |||
<input name="type" type="hidden" value="verify_ssh"> | |||
<button class="ui green button"> |
@@ -44,13 +44,28 @@ export function initFootLanguageMenu() { | |||
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() { | |||
$(document).on('keypress', '.ui.button', (e) => { | |||
if (e.keyCode === 13 || e.keyCode === 32) { // enter key or space bar |
@@ -1,5 +1,6 @@ | |||
import $ from 'jquery'; | |||
import attachTribute from '../tribute.js'; | |||
import {handleGlobalEnterQuickSubmit} from '../common-global.js'; | |||
/** | |||
* @returns {EasyMDE} | |||
@@ -71,9 +72,12 @@ export async function createCommentEasyMDE(textarea, easyMDEOptions = {}) { | |||
title: 'Revert to simple textarea', | |||
}, | |||
], ...easyMDEOptions}); | |||
const inputField = easyMDE.codemirror.getInputField(); | |||
inputField.classList.add('js-quick-submit'); | |||
easyMDE.codemirror.setOption('extraKeys', { | |||
'Cmd-Enter': codeMirrorQuickSubmit, | |||
'Ctrl-Enter': codeMirrorQuickSubmit, | |||
Enter: (cm) => { | |||
const tributeContainer = document.querySelector('.tribute-container'); | |||
if (!tributeContainer || tributeContainer.style.display === 'none') { | |||
@@ -149,3 +153,12 @@ export function validateTextareaNonEmpty($textarea) { | |||
$mdeInputField.prop('required', false); | |||
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()); | |||
} |
@@ -355,6 +355,11 @@ async function onEditContent(event) { | |||
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', () => { | |||
$renderContent.show(); | |||
$editContentZone.hide(); | |||
@@ -362,7 +367,8 @@ async function onEditContent(event) { | |||
dz.emit('reload'); | |||
} | |||
}); | |||
$editContentZone.find('.save.button').on('click', () => { | |||
$saveButton.on('click', () => { | |||
$renderContent.show(); | |||
$editContentZone.hide(); | |||
const $attachments = $dropzone.find('.files').find('[name=files]').map(function () { | |||
@@ -400,7 +406,7 @@ async function onEditContent(event) { | |||
initCommentContent(); | |||
}); | |||
}); | |||
} else { | |||
} else { // use existing form | |||
$textarea = $segment.find('textarea'); | |||
easyMDE = getAttachedEasyMDE($textarea); | |||
} |
@@ -1,6 +1,6 @@ | |||
import $ from 'jquery'; | |||
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'; | |||
const {csrfToken} = window.config; | |||
@@ -122,10 +122,12 @@ async function initRepoWikiFormEditor() { | |||
] | |||
}); | |||
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', () => { | |||
if (!validateTextareaNonEmpty($editArea)) { |