From 066a99b6e9d0849b477858c9aac274c2f81bb367 Mon Sep 17 00:00:00 2001 From: Sam Bigelow Date: Fri, 14 Dec 2018 12:56:25 -0500 Subject: Add markdown buttons to file editor Currently, we have markdown files in many places (e.g. comments, new issues, etc.). This Merge Request detects if the file being edited is a markdown file and adds markdown buttons and their functionality to the single file editor (Not the web IDE) --- spec/javascripts/lib/utils/text_markdown_spec.js | 387 ++++++++++++++--------- 1 file changed, 234 insertions(+), 153 deletions(-) (limited to 'spec/javascripts/lib/utils') diff --git a/spec/javascripts/lib/utils/text_markdown_spec.js b/spec/javascripts/lib/utils/text_markdown_spec.js index f71d27eb4e4..df4029555bb 100644 --- a/spec/javascripts/lib/utils/text_markdown_spec.js +++ b/spec/javascripts/lib/utils/text_markdown_spec.js @@ -13,215 +13,296 @@ describe('init markdown', () => { textArea.parentNode.removeChild(textArea); }); - describe('without selection', () => { - it('inserts the tag on an empty line', () => { - const initialValue = ''; + describe('textArea', () => { + describe('without selection', () => { + it('inserts the tag on an empty line', () => { + const initialValue = ''; - textArea.value = initialValue; - textArea.selectionStart = 0; - textArea.selectionEnd = 0; - - insertMarkdownText({ - textArea, - text: textArea.value, - tag: '*', - blockTag: null, - selected: '', - wrap: false, - }); - - expect(textArea.value).toEqual(`${initialValue}* `); - }); - - it('inserts the tag on a new line if the current one is not empty', () => { - const initialValue = 'some text'; + textArea.value = initialValue; + textArea.selectionStart = 0; + textArea.selectionEnd = 0; - textArea.value = initialValue; - textArea.setSelectionRange(initialValue.length, initialValue.length); + insertMarkdownText({ + textArea, + text: textArea.value, + tag: '*', + blockTag: null, + selected: '', + wrap: false, + }); - insertMarkdownText({ - textArea, - text: textArea.value, - tag: '*', - blockTag: null, - selected: '', - wrap: false, + expect(textArea.value).toEqual(`${initialValue}* `); }); - expect(textArea.value).toEqual(`${initialValue}\n* `); - }); + it('inserts the tag on a new line if the current one is not empty', () => { + const initialValue = 'some text'; - it('inserts the tag on the same line if the current line only contains spaces', () => { - const initialValue = ' '; + textArea.value = initialValue; + textArea.setSelectionRange(initialValue.length, initialValue.length); - textArea.value = initialValue; - textArea.setSelectionRange(initialValue.length, initialValue.length); + insertMarkdownText({ + textArea, + text: textArea.value, + tag: '*', + blockTag: null, + selected: '', + wrap: false, + }); - insertMarkdownText({ - textArea, - text: textArea.value, - tag: '*', - blockTag: null, - selected: '', - wrap: false, + expect(textArea.value).toEqual(`${initialValue}\n* `); }); - expect(textArea.value).toEqual(`${initialValue}* `); - }); + it('inserts the tag on the same line if the current line only contains spaces', () => { + const initialValue = ' '; - it('inserts the tag on the same line if the current line only contains tabs', () => { - const initialValue = '\t\t\t'; + textArea.value = initialValue; + textArea.setSelectionRange(initialValue.length, initialValue.length); - textArea.value = initialValue; - textArea.setSelectionRange(initialValue.length, initialValue.length); + insertMarkdownText({ + textArea, + text: textArea.value, + tag: '*', + blockTag: null, + selected: '', + wrap: false, + }); - insertMarkdownText({ - textArea, - text: textArea.value, - tag: '*', - blockTag: null, - selected: '', - wrap: false, + expect(textArea.value).toEqual(`${initialValue}* `); }); - expect(textArea.value).toEqual(`${initialValue}* `); - }); + it('inserts the tag on the same line if the current line only contains tabs', () => { + const initialValue = '\t\t\t'; - it('places the cursor inside the tags', () => { - const start = 'lorem '; - const end = ' ipsum'; - const tag = '*'; + textArea.value = initialValue; + textArea.setSelectionRange(initialValue.length, initialValue.length); - textArea.value = `${start}${end}`; - textArea.setSelectionRange(start.length, start.length); + insertMarkdownText({ + textArea, + text: textArea.value, + tag: '*', + blockTag: null, + selected: '', + wrap: false, + }); - insertMarkdownText({ - textArea, - text: textArea.value, - tag, - blockTag: null, - selected: '', - wrap: true, + expect(textArea.value).toEqual(`${initialValue}* `); }); - expect(textArea.value).toEqual(`${start}**${end}`); + it('places the cursor inside the tags', () => { + const start = 'lorem '; + const end = ' ipsum'; + const tag = '*'; - // cursor placement should be between tags - expect(textArea.selectionStart).toBe(start.length + tag.length); - }); - }); + textArea.value = `${start}${end}`; + textArea.setSelectionRange(start.length, start.length); - describe('with selection', () => { - const text = 'initial selected value'; - const selected = 'selected'; - beforeEach(() => { - textArea.value = text; - const selectedIndex = text.indexOf(selected); - textArea.setSelectionRange(selectedIndex, selectedIndex + selected.length); - }); + insertMarkdownText({ + textArea, + text: textArea.value, + tag, + blockTag: null, + selected: '', + wrap: true, + }); - it('applies the tag to the selected value', () => { - const selectedIndex = text.indexOf(selected); - const tag = '*'; + expect(textArea.value).toEqual(`${start}**${end}`); - insertMarkdownText({ - textArea, - text: textArea.value, - tag, - blockTag: null, - selected, - wrap: true, + // cursor placement should be between tags + expect(textArea.selectionStart).toBe(start.length + tag.length); }); - - expect(textArea.value).toEqual(text.replace(selected, `*${selected}*`)); - - // cursor placement should be after selection + 2 tag lengths - expect(textArea.selectionStart).toBe(selectedIndex + selected.length + 2 * tag.length); }); - it('replaces the placeholder in the tag', () => { - insertMarkdownText({ - textArea, - text: textArea.value, - tag: '[{text}](url)', - blockTag: null, - selected, - wrap: false, + describe('with selection', () => { + const text = 'initial selected value'; + const selected = 'selected'; + beforeEach(() => { + textArea.value = text; + const selectedIndex = text.indexOf(selected); + textArea.setSelectionRange(selectedIndex, selectedIndex + selected.length); }); - expect(textArea.value).toEqual(text.replace(selected, `[${selected}](url)`)); - }); + it('applies the tag to the selected value', () => { + const selectedIndex = text.indexOf(selected); + const tag = '*'; - describe('and text to be selected', () => { - const tag = '[{text}](url)'; - const select = 'url'; - - it('selects the text', () => { insertMarkdownText({ textArea, text: textArea.value, tag, blockTag: null, selected, - wrap: false, - select, + wrap: true, }); - const expectedText = text.replace(selected, `[${selected}](url)`); + expect(textArea.value).toEqual(text.replace(selected, `*${selected}*`)); - expect(textArea.value).toEqual(expectedText); - expect(textArea.selectionStart).toEqual(expectedText.indexOf(select)); - expect(textArea.selectionEnd).toEqual(expectedText.indexOf(select) + select.length); + // cursor placement should be after selection + 2 tag lengths + expect(textArea.selectionStart).toBe(selectedIndex + selected.length + 2 * tag.length); }); - it('selects the right text when multiple tags are present', () => { - const initialValue = `${tag} ${tag} ${selected}`; - textArea.value = initialValue; - const selectedIndex = initialValue.indexOf(selected); - textArea.setSelectionRange(selectedIndex, selectedIndex + selected.length); + it('replaces the placeholder in the tag', () => { insertMarkdownText({ textArea, text: textArea.value, - tag, + tag: '[{text}](url)', blockTag: null, selected, wrap: false, - select, }); - const expectedText = initialValue.replace(selected, `[${selected}](url)`); - - expect(textArea.value).toEqual(expectedText); - expect(textArea.selectionStart).toEqual(expectedText.lastIndexOf(select)); - expect(textArea.selectionEnd).toEqual(expectedText.lastIndexOf(select) + select.length); + expect(textArea.value).toEqual(text.replace(selected, `[${selected}](url)`)); }); - it('should support selected urls', () => { - const expectedUrl = 'http://www.gitlab.com'; - const expectedSelectionText = 'text'; - const expectedText = `text [${expectedSelectionText}](${expectedUrl}) text`; - const initialValue = `text ${expectedUrl} text`; + describe('and text to be selected', () => { + const tag = '[{text}](url)'; + const select = 'url'; + + it('selects the text', () => { + insertMarkdownText({ + textArea, + text: textArea.value, + tag, + blockTag: null, + selected, + wrap: false, + select, + }); + + const expectedText = text.replace(selected, `[${selected}](url)`); + + expect(textArea.value).toEqual(expectedText); + expect(textArea.selectionStart).toEqual(expectedText.indexOf(select)); + expect(textArea.selectionEnd).toEqual(expectedText.indexOf(select) + select.length); + }); - textArea.value = initialValue; - const selectedIndex = initialValue.indexOf(expectedUrl); - textArea.setSelectionRange(selectedIndex, selectedIndex + expectedUrl.length); + it('selects the right text when multiple tags are present', () => { + const initialValue = `${tag} ${tag} ${selected}`; + textArea.value = initialValue; + const selectedIndex = initialValue.indexOf(selected); + textArea.setSelectionRange(selectedIndex, selectedIndex + selected.length); + insertMarkdownText({ + textArea, + text: textArea.value, + tag, + blockTag: null, + selected, + wrap: false, + select, + }); + + const expectedText = initialValue.replace(selected, `[${selected}](url)`); + + expect(textArea.value).toEqual(expectedText); + expect(textArea.selectionStart).toEqual(expectedText.lastIndexOf(select)); + expect(textArea.selectionEnd).toEqual(expectedText.lastIndexOf(select) + select.length); + }); - insertMarkdownText({ - textArea, - text: textArea.value, - tag, - blockTag: null, - selected: expectedUrl, - wrap: false, - select, + it('should support selected urls', () => { + const expectedUrl = 'http://www.gitlab.com'; + const expectedSelectionText = 'text'; + const expectedText = `text [${expectedSelectionText}](${expectedUrl}) text`; + const initialValue = `text ${expectedUrl} text`; + + textArea.value = initialValue; + const selectedIndex = initialValue.indexOf(expectedUrl); + textArea.setSelectionRange(selectedIndex, selectedIndex + expectedUrl.length); + + insertMarkdownText({ + textArea, + text: textArea.value, + tag, + blockTag: null, + selected: expectedUrl, + wrap: false, + select, + }); + + expect(textArea.value).toEqual(expectedText); + expect(textArea.selectionStart).toEqual(expectedText.indexOf(expectedSelectionText, 1)); + expect(textArea.selectionEnd).toEqual( + expectedText.indexOf(expectedSelectionText, 1) + expectedSelectionText.length, + ); }); + }); + }); + }); + + describe('Ace Editor', () => { + let editor; + + beforeEach(() => { + editor = { + getSelectionRange: () => ({ + start: 0, + end: 0, + }), + getValue: () => 'this is text \n in two lines', + insert: () => {}, + navigateLeft: () => {}, + }; + }); + + it('uses ace editor insert text when editor is passed in', () => { + spyOn(editor, 'insert'); - expect(textArea.value).toEqual(expectedText); - expect(textArea.selectionStart).toEqual(expectedText.indexOf(expectedSelectionText, 1)); - expect(textArea.selectionEnd).toEqual( - expectedText.indexOf(expectedSelectionText, 1) + expectedSelectionText.length, - ); + insertMarkdownText({ + text: editor.getValue, + tag: '*', + blockTag: null, + selected: '', + wrap: false, + editor, + }); + + expect(editor.insert).toHaveBeenCalled(); + }); + + it('adds block tags on line above and below selection', () => { + spyOn(editor, 'insert'); + + const selected = 'this text \n is multiple \n lines'; + const text = `before \n ${selected} \n after`; + + insertMarkdownText({ + text, + tag: '', + blockTag: '***', + selected, + wrap: true, + editor, + }); + + expect(editor.insert).toHaveBeenCalledWith(`***\n${selected}\n***`); + }); + + it('uses ace editor to navigate back tag length when nothing is selected', () => { + spyOn(editor, 'navigateLeft'); + + insertMarkdownText({ + text: editor.getValue, + tag: '*', + blockTag: null, + selected: '', + wrap: true, + editor, }); + + expect(editor.navigateLeft).toHaveBeenCalledWith(1); + }); + + it('ace editor does not navigate back when there is selected text', () => { + spyOn(editor, 'navigateLeft'); + + insertMarkdownText({ + text: editor.getValue, + tag: '*', + blockTag: null, + selected: 'foobar', + wrap: true, + editor, + }); + + expect(editor.navigateLeft).not.toHaveBeenCalled(); }); }); }); -- cgit v1.2.1