Commit c6cb9896 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch 'markdown-strikethrough' into 'master'

Improve strikethrough in Markdown editor

See merge request gitlab-org/gitlab!81092
parents d1c7a767 103a129e
......@@ -131,6 +131,13 @@ export const ITALIC_TEXT = {
customizable: false,
};
export const STRIKETHROUGH_TEXT = {
id: 'editing.strikethroughText',
description: __('Strikethrough text'),
defaultKeys: ['mod+shift+x'],
customizable: false,
};
export const LINK_TEXT = {
id: 'editing.linkText',
description: __('Link text'),
......@@ -511,7 +518,14 @@ export const GLOBAL_SHORTCUTS_GROUP = {
export const EDITING_SHORTCUTS_GROUP = {
id: 'editing',
name: __('Editing'),
keybindings: [BOLD_TEXT, ITALIC_TEXT, LINK_TEXT, TOGGLE_MARKDOWN_PREVIEW, EDIT_RECENT_COMMENT],
keybindings: [
BOLD_TEXT,
ITALIC_TEXT,
STRIKETHROUGH_TEXT,
LINK_TEXT,
TOGGLE_MARKDOWN_PREVIEW,
EDIT_RECENT_COMMENT,
],
};
export const WIKI_SHORTCUTS_GROUP = {
......
......@@ -574,6 +574,10 @@ class GfmAutoComplete {
// Do not match if there is no `~` before the cursor
return null;
}
if (subtext.endsWith('~~')) {
// Do not match if there are two consecutive `~` characters (strikethrough) before the cursor
return null;
}
const lastCandidate = subtext.split(flag).pop();
if (labels.find((label) => label.title.startsWith(lastCandidate))) {
return lastCandidate;
......
<script>
import { GlPopover, GlButton, GlTooltipDirective, GlTabs, GlTab } from '@gitlab/ui';
import $ from 'jquery';
import { keysFor, BOLD_TEXT, ITALIC_TEXT, LINK_TEXT } from '~/behaviors/shortcuts/keybindings';
import {
keysFor,
BOLD_TEXT,
ITALIC_TEXT,
STRIKETHROUGH_TEXT,
LINK_TEXT,
} from '~/behaviors/shortcuts/keybindings';
import { getSelectedFragment } from '~/lib/utils/common_utils';
import { s__, __ } from '~/locale';
import { CopyAsGFM } from '../../../behaviors/markdown/copy_as_gfm';
......@@ -149,6 +155,7 @@ export default {
shortcuts: {
bold: keysFor(BOLD_TEXT),
italic: keysFor(ITALIC_TEXT),
strikethrough: keysFor(STRIKETHROUGH_TEXT),
link: keysFor(LINK_TEXT),
},
i18n: {
......@@ -199,6 +206,16 @@ export default {
:shortcuts="$options.shortcuts.italic"
icon="italic"
/>
<toolbar-button
tag="~~"
:button-title="
sprintf(s__('MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)'), {
modifierKey,
})
"
:shortcuts="$options.shortcuts.strikethrough"
icon="strikethrough"
/>
<toolbar-button
:prepend="true"
:tag="tag"
......
......@@ -9,6 +9,10 @@
data: { "md-tag" => "_", "md-shortcuts": '["mod+i"]' },
title: sprintf(s_("MarkdownEditor|Add italic text (%{modifier_key}I)") % { modifier_key: modifier_key }) })
= markdown_toolbar_button({ icon: "strikethrough",
data: { "md-tag" => "~~", "md-shortcuts": '["mod+shift+x"]' },
title: sprintf(s_("MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)") % { modifier_key: modifier_key }) })
= markdown_toolbar_button({ icon: "quote", data: { "md-tag" => "> ", "md-prepend" => true }, title: _("Insert a quote") })
= markdown_toolbar_button({ icon: "code", data: { "md-tag" => "`", "md-block" => "```" }, title: _("Insert code") })
......
......@@ -51,6 +51,7 @@ descriptions):
| <kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>p</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>p</kbd> | Toggle Markdown preview when editing text in a text field that has **Write** and **Preview** tabs at the top. |
| <kbd>Command</kbd> + <kbd>b</kbd> | <kbd>Control</kbd> + <kbd>b</kbd> | Bold the selected text (surround it with `**`). |
| <kbd>Command</kbd> + <kbd>i</kbd> | <kbd>Control</kbd> + <kbd>i</kbd> | Italicize the selected text (surround it with `_`). |
| <kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>s</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>s</kbd> | Strike through the selected text (surround it with `~~`). |
| <kbd>Command</kbd> + <kbd>k</kbd> | <kbd>Control</kbd> + <kbd>k</kbd> | Add a link (surround the selected text with `[]()`). |
The shortcuts for editing in text fields are always enabled, even if other
......
......@@ -22383,6 +22383,12 @@ msgstr ""
msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifierKey}⇧X)"
msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
......@@ -35087,6 +35093,9 @@ msgstr ""
msgid "Strikethrough"
msgstr ""
msgid "Strikethrough text"
msgstr ""
msgid "Subgroup information"
msgstr ""
......
......@@ -111,6 +111,20 @@ RSpec.describe 'GFM autocomplete', :js do
fill_in 'Comment', with: "test\n\n@"
expect(find_autocomplete_menu).to be_visible
end
it 'does not open label autocomplete menu after strikethrough', :aggregate_failures do
fill_in 'Comment', with: "~~"
expect(page).not_to have_css('.atwho-view')
fill_in 'Comment', with: "~~gone~~"
expect(page).not_to have_css('.atwho-view')
fill_in 'Comment', with: "~"
expect(find_autocomplete_menu).to be_visible
fill_in 'Comment', with: "test\n\n~"
expect(find_autocomplete_menu).to be_visible
end
end
context 'xss checks' do
......
......@@ -37,6 +37,14 @@ RSpec.describe 'Markdown keyboard shortcuts', :js do
expect(markdown_field.value).to eq('_italic_')
end
it 'strikes text when <modifier>+<shift>+x is pressed' do
type_and_select('strikethrough')
markdown_field.send_keys([modifier_key, :shift, 'x'])
expect(markdown_field.value).to eq('~~strikethrough~~')
end
it 'links text when <modifier>+K is pressed' do
type_and_select('link')
......
......@@ -76,7 +76,7 @@ describe('Markdown field component', () => {
const getPreviewLink = () => subject.findByTestId('preview-tab');
const getWriteLink = () => subject.findByTestId('write-tab');
const getMarkdownButton = () => subject.find('.js-md');
const getAllMarkdownButtons = () => subject.findAll('.js-md');
const getListBulletedButton = () => subject.findAll('.js-md[title="Add a bullet list"]');
const getVideo = () => subject.find('video');
const getAttachButton = () => subject.find('.button-attach-file');
const clickAttachButton = () => getAttachButton().trigger('click');
......@@ -185,7 +185,7 @@ describe('Markdown field component', () => {
it('converts a line', async () => {
const textarea = subject.find('textarea').element;
textarea.setSelectionRange(0, 0);
const markdownButton = getAllMarkdownButtons().wrappers[5];
const markdownButton = getListBulletedButton();
markdownButton.trigger('click');
await nextTick();
......@@ -195,7 +195,7 @@ describe('Markdown field component', () => {
it('converts multiple lines', async () => {
const textarea = subject.find('textarea').element;
textarea.setSelectionRange(0, 50);
const markdownButton = getAllMarkdownButtons().wrappers[5];
const markdownButton = getListBulletedButton();
markdownButton.trigger('click');
await nextTick();
......
......@@ -46,6 +46,7 @@ describe('Markdown field header component', () => {
const buttons = [
'Add bold text (⌘B)',
'Add italic text (⌘I)',
'Add strikethrough text (⌘⇧X)',
'Insert a quote',
'Insert suggestion',
'Insert code',
......
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