From 13b7854c659e959d3469ea52cf9aca86ea8b08be Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Wed, 19 Aug 2020 21:26:22 +0200 Subject: [PATCH] made the addCodeFences function also work without selections (#428) * made the addCodeFences function also work without selections changed tests accordingly * add codeFence change in CHANGELOG.md --- CHANGELOG.md | 1 + cypress/integration/toolbar.spec.ts | 54 ++++++++++++++----- .../tool-bar/utils/toolbarButtonUtils.test.ts | 37 +++++++++++-- .../tool-bar/utils/toolbarButtonUtils.ts | 16 +++++- 4 files changed, 91 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18b5e189f..6aac82bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - Asciinema videos may now be embedded by pasting the URL of one video into a single line - The Toolbar includes an EmojiPicker - Added shortcodes for [fork-awesome icons](https://forkaweso.me/Fork-Awesome/icons/) (e.g. `:fa-picture-o:`) +- The code button now adds code fences even if the user selected nothing beforehand ### Changed diff --git a/cypress/integration/toolbar.spec.ts b/cypress/integration/toolbar.spec.ts index 0108c9b50..d7eb421b6 100644 --- a/cypress/integration/toolbar.spec.ts +++ b/cypress/integration/toolbar.spec.ts @@ -85,18 +85,48 @@ describe('Toolbar', () => { .should('have.text', `## ${testText}`) }) - it('code', () => { - cy.get('.CodeMirror textarea') - .type(`${testText}`) - .type('{ctrl}a') - cy.get('.fa-code') - .click() - cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span') - .should('have.text', '```') - cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span') - .should('have.text', testText) - cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span') - .should('have.text', '```') + describe('code', () => { + it('nothing selected empty line', () => { + cy.get('.CodeMirror textarea') + .type(`${testText}`) + .type('{ctrl}a') + .type('{backspace}') + cy.get('.fa-code') + .click() + cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span') + .should('have.text', '```') + cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span') + .should('have.text', '```') + }) + + it('nothing selected non line', () => { + cy.get('.CodeMirror textarea') + .type(`${testText}`) + .type('{ctrl}a') + .type('{leftArrow}') + cy.get('.fa-code') + .click() + cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span') + .should('have.text', '```') + cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span') + .should('have.text', testText) + cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span') + .should('have.text', '```') + }) + + it('line selected', () => { + cy.get('.CodeMirror textarea') + .type(`${testText}`) + .type('{ctrl}a') + cy.get('.fa-code') + .click() + cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span') + .should('have.text', '```') + cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span') + .should('have.text', testText) + cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span') + .should('have.text', '```') + }) }) it('quote', () => { diff --git a/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.test.ts b/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.test.ts index 40290aba1..245d7eacf 100644 --- a/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.test.ts +++ b/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.test.ts @@ -786,8 +786,9 @@ describe('test addHeaderLevel', () => { describe('test addCodeFences', () => { const { cursor, firstLine, multiline, multilineOffset } = buildRanges() - it('just cursor', done => { + it('just cursor empty line', done => { Mock.extend(editor).with({ + getSelection: () => '', listSelections: () => ( Mock.of([{ anchor: cursor.from, @@ -796,14 +797,40 @@ describe('test addCodeFences', () => { to: () => cursor.to, empty: () => true }]) - ) + ), + getLine: (): string => '', + replaceRange: (replacement: string | string[]) => { + expect(replacement).toEqual('```\n\n```') + done() + } }) - strikeThroughSelection(editor) - done() + addCodeFences(editor) + }) + + it('just cursor nonempty line', done => { + Mock.extend(editor).with({ + getSelection: () => '', + listSelections: () => ( + Mock.of([{ + anchor: cursor.from, + head: cursor.to, + from: () => cursor.from, + to: () => cursor.to, + empty: () => true + }]) + ), + getLine: (): string => '1st line', + replaceRange: (replacement: string | string[]) => { + expect(replacement).toEqual('```\n1st line\n```') + done() + } + }) + addCodeFences(editor) }) it('1st line', done => { Mock.extend(editor).with({ + getSelection: () => testContent, listSelections: () => ( Mock.of([{ anchor: firstLine.from, @@ -825,6 +852,7 @@ describe('test addCodeFences', () => { it('multiple lines', done => { Mock.extend(editor).with({ + getSelection: () => testContent, listSelections: () => ( Mock.of([{ anchor: multiline.from, @@ -846,6 +874,7 @@ describe('test addCodeFences', () => { it('multiple lines with offset', done => { Mock.extend(editor).with({ + getSelection: () => testContent, listSelections: () => ( Mock.of([{ anchor: multilineOffset.from, diff --git a/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.ts b/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.ts index 27c323926..ed700aa8e 100644 --- a/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.ts +++ b/src/components/editor/editor-pane/tool-bar/utils/toolbarButtonUtils.ts @@ -11,7 +11,7 @@ export const superscriptSelection = (editor: Editor): void => wrapTextWith(edito export const markSelection = (editor: Editor): void => wrapTextWith(editor, '==') export const addHeaderLevel = (editor: Editor): void => changeLines(editor, line => line.startsWith('#') ? `#${line}` : `# ${line}`) -export const addCodeFences = (editor: Editor): void => wrapTextWith(editor, '```\n', '\n```') +export const addCodeFences = (editor: Editor): void => wrapTextWithOrJustPut(editor, '```\n', '\n```') export const addQuotes = (editor: Editor): void => insertOnStartOfLines(editor, '> ') export const addList = (editor: Editor): void => createList(editor, () => '- ') @@ -48,6 +48,20 @@ export const wrapTextWith = (editor: Editor, symbol: string, endSymbol?: string) editor.setSelections(ranges) } +const wrapTextWithOrJustPut = (editor: Editor, symbol: string, endSymbol?: string): void => { + if (!editor.getSelection()) { + const cursor = editor.getCursor() + const lineNumber = cursor.line + const line = editor.getLine(lineNumber) + const replacement = /\s*\\n/.exec(line) ? `${symbol}${endSymbol ?? ''}` : `${symbol}${line}${endSymbol ?? ''}` + editor.replaceRange(replacement, + { line: cursor.line, ch: 0 }, + { line: cursor.line, ch: line.length }, + '+input') + } + wrapTextWith(editor, symbol, endSymbol ?? symbol) +} + export const insertOnStartOfLines = (editor: Editor, symbol: string): void => { const cursor = editor.getCursor() const ranges = editor.listSelections()