From f0402e3f385e5466595b56388f2372932d637896 Mon Sep 17 00:00:00 2001 From: Brett Walker Date: Wed, 11 Sep 2019 13:58:15 -0500 Subject: [PATCH 1/2] Surround selected text with typed char MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in markdown fields. Supports - ` backtick - ‘ single quotes - “ double quotes - _ underscore (wraps the text in the markdown italic character) - * asterisk (wraps the text in the markdown bold characters, **) - [ brackets - < angle brackets - ( parentheses --- .../javascripts/lib/utils/text_markdown.js | 36 +++++++++++++++++++ .../unreleased/bw-surround-text-wth-char.yml | 5 +++ spec/frontend/lib/utils/text_markdown_spec.js | 34 +++++++++++++++--- 3 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/bw-surround-text-wth-char.yml diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index 8d23d177410b43..c34bf21f5b0ba2 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -303,7 +303,42 @@ function updateText({ textArea, tag, cursorOffset, blockTag, wrap, select, tagCo }); } +/* eslint-disable @gitlab/require-i18n-strings */ +export function keypressNoteText(e) { + if (this.selectionStart === this.selectionEnd) { + return; + } + const keys = { + '*': '**{text}**', // wraps with bold character + _: '_{text}_', // wraps with italic character + '`': '`{text}`', // wraps with inline character + "'": "'{text}'", // single quotes + '"': '"{text}"', // double quotes + '[': '[{text}]', // brackets + '{': '{{text}}', // braces + '(': '({text})', // parentheses + '<': '<{text}>', // angle brackets + }; + const tag = keys[e.key]; + + if (tag) { + e.preventDefault(); + + updateText({ + tag, + textArea: this, + blockTag: '', + wrap: true, + select: '', + tagContent: '', + }); + + } +} +/* eslint-enable @gitlab/require-i18n-strings */ + export function addMarkdownListeners(form) { + $('.markdown-area').on('keydown', keypressNoteText); return $('.js-md', form) .off('click') .on('click', function() { @@ -342,5 +377,6 @@ export function addEditorMarkdownListeners(editor) { } export function removeMarkdownListeners(form) { + $('.markdown-area').off('keydown'); return $('.js-md', form).off('click'); } diff --git a/changelogs/unreleased/bw-surround-text-wth-char.yml b/changelogs/unreleased/bw-surround-text-wth-char.yml new file mode 100644 index 00000000000000..7395bb9c26b977 --- /dev/null +++ b/changelogs/unreleased/bw-surround-text-wth-char.yml @@ -0,0 +1,5 @@ +--- +title: Surround selected text in markdown fields on certain key presses +merge_request: 25748 +author: +type: added diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js index 2e52958a8289f7..1aaae80dcdf3b4 100644 --- a/spec/frontend/lib/utils/text_markdown_spec.js +++ b/spec/frontend/lib/utils/text_markdown_spec.js @@ -1,4 +1,4 @@ -import { insertMarkdownText } from '~/lib/utils/text_markdown'; +import { insertMarkdownText, keypressNoteText } from '~/lib/utils/text_markdown'; describe('init markdown', () => { let textArea; @@ -115,14 +115,15 @@ describe('init markdown', () => { describe('with selection', () => { const text = 'initial selected value'; const selected = 'selected'; + let selectedIndex; + beforeEach(() => { textArea.value = text; - const selectedIndex = text.indexOf(selected); + selectedIndex = text.indexOf(selected); textArea.setSelectionRange(selectedIndex, selectedIndex + selected.length); }); it('applies the tag to the selected value', () => { - const selectedIndex = text.indexOf(selected); const tag = '*'; insertMarkdownText({ @@ -153,6 +154,29 @@ describe('init markdown', () => { expect(textArea.value).toEqual(text.replace(selected, `[${selected}](url)`)); }); + it.each` + key | expected + ${'['} | ${`[${selected}]`} + ${'*'} | ${`**${selected}**`} + ${"'"} | ${`'${selected}'`} + ${'_'} | ${`_${selected}_`} + ${'`'} | ${`\`${selected}\``} + ${'"'} | ${`"${selected}"`} + ${'{'} | ${`{${selected}}`} + ${'('} | ${`(${selected})`} + ${'<'} | ${`<${selected}>`} + `('generates $expected when $key is pressed', ({ key, expected }) => { + const event = new KeyboardEvent('keydown', { key }); + + textArea.addEventListener('keydown', keypressNoteText); + textArea.dispatchEvent(event); + + expect(textArea.value).toEqual(text.replace(selected, expected)); + + // cursor placement should be after selection + 2 tag lengths + expect(textArea.selectionStart).toBe(selectedIndex + expected.length); + }); + describe('and text to be selected', () => { const tag = '[{text}](url)'; const select = 'url'; @@ -178,7 +202,7 @@ describe('init markdown', () => { it('selects the right text when multiple tags are present', () => { const initialValue = `${tag} ${tag} ${selected}`; textArea.value = initialValue; - const selectedIndex = initialValue.indexOf(selected); + selectedIndex = initialValue.indexOf(selected); textArea.setSelectionRange(selectedIndex, selectedIndex + selected.length); insertMarkdownText({ textArea, @@ -204,7 +228,7 @@ describe('init markdown', () => { const initialValue = `text ${expectedUrl} text`; textArea.value = initialValue; - const selectedIndex = initialValue.indexOf(expectedUrl); + selectedIndex = initialValue.indexOf(expectedUrl); textArea.setSelectionRange(selectedIndex, selectedIndex + expectedUrl.length); insertMarkdownText({ -- GitLab From 70aec343a5d097058957e0c6515e486d0b04200f Mon Sep 17 00:00:00 2001 From: Brett Walker Date: Thu, 6 Aug 2020 18:02:02 -0500 Subject: [PATCH 2/2] Properly turn off markdown keydown listener for specific text area --- app/assets/javascripts/lib/utils/text_markdown.js | 5 ++--- changelogs/unreleased/bw-surround-text-wth-char.yml | 2 +- spec/features/projects/wiki/markdown_preview_spec.rb | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index c34bf21f5b0ba2..45d06e8e9755a6 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -332,13 +332,12 @@ export function keypressNoteText(e) { select: '', tagContent: '', }); - } } /* eslint-enable @gitlab/require-i18n-strings */ export function addMarkdownListeners(form) { - $('.markdown-area').on('keydown', keypressNoteText); + $('.markdown-area', form).on('keydown', keypressNoteText); return $('.js-md', form) .off('click') .on('click', function() { @@ -377,6 +376,6 @@ export function addEditorMarkdownListeners(editor) { } export function removeMarkdownListeners(form) { - $('.markdown-area').off('keydown'); + $('.markdown-area', form).off('keydown', keypressNoteText); return $('.js-md', form).off('click'); } diff --git a/changelogs/unreleased/bw-surround-text-wth-char.yml b/changelogs/unreleased/bw-surround-text-wth-char.yml index 7395bb9c26b977..506271f13c1f54 100644 --- a/changelogs/unreleased/bw-surround-text-wth-char.yml +++ b/changelogs/unreleased/bw-surround-text-wth-char.yml @@ -1,5 +1,5 @@ --- title: Surround selected text in markdown fields on certain key presses -merge_request: 25748 +merge_request: 37151 author: type: added diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 8eba2c985956f8..8f2fb9e827c942 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -8,6 +8,7 @@ let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') } let(:wiki_content) do <<-HEREDOC +Some text so key event for [ does not trigger an incorrect replacement. [regular link](regular) [relative link 1](../relative) [relative link 2](./relative) -- GitLab