From bafa3e9dbfd1fbc847acd8876e20ce7d76be16f7 Mon Sep 17 00:00:00 2001 From: Cory Date: Tue, 16 Aug 2016 17:52:40 -0400 Subject: [PATCH] fix(links): Ensure that CTRL+K on Windows toggles link. Fixes #452 --- src/js/editor/key-commands.js | 75 +++++----- tests/acceptance/editor-key-commands-test.js | 136 ++++++++++++------- tests/test-helpers.js | 1 + 3 files changed, 133 insertions(+), 79 deletions(-) diff --git a/src/js/editor/key-commands.js b/src/js/editor/key-commands.js index cd885e505..e43053857 100644 --- a/src/js/editor/key-commands.js +++ b/src/js/editor/key-commands.js @@ -25,6 +25,44 @@ function gotoEndOfLine(editor) { }); } +function deleteToEndOfSection(editor) { + let { range } = editor; + if (range.isCollapsed) { + let { head, head: { section } } = range; + range = head.toRange(section.tailPosition()); + } + editor.run(postEditor => { + let nextPosition = postEditor.deleteRange(range); + postEditor.setRange(nextPosition); + }); +} + +function toggleLink(editor) { + if (editor.range.isCollapsed) { + return; + } + + let selectedText = editor.cursor.selectedText(); + let defaultUrl = ''; + if (selectedText.indexOf('http') !== -1) { defaultUrl = selectedText; } + + let {range} = editor; + let hasLink = editor.detectMarkupInRange(range, 'a'); + + if (hasLink) { + editor.run(postEditor => postEditor.toggleMarkup('a')); + } else { + editor.showPrompt('Enter a URL', defaultUrl, url => { + if (!url) { return; } + + editor.run(postEditor => { + let markup = postEditor.builder.createMarkup('a', {href: url}); + postEditor.toggleMarkup(markup); + }); + }); + } +} + export const DEFAULT_KEY_COMMANDS = [{ str: 'META+B', run(editor) { @@ -48,15 +86,11 @@ export const DEFAULT_KEY_COMMANDS = [{ }, { str: 'CTRL+K', run(editor) { - let { range } = editor; - if (range.isCollapsed) { - let { head, head: { section } } = range; - range = head.toRange(section.tailPosition()); + if (Browser.isMac()) { + return deleteToEndOfSection(editor); + } else if (Browser.isWin()) { + return toggleLink(editor); } - editor.run(postEditor => { - let nextPosition = postEditor.deleteRange(range); - postEditor.setRange(nextPosition); - }); } }, { str: 'CTRL+A', @@ -84,30 +118,9 @@ export const DEFAULT_KEY_COMMANDS = [{ }, { str: 'META+K', run(editor) { - if (editor.range.isCollapsed) { - return; - } + return toggleLink(editor); + }, - let selectedText = editor.cursor.selectedText(); - let defaultUrl = ''; - if (selectedText.indexOf('http') !== -1) { defaultUrl = selectedText; } - - let {range} = editor; - let hasLink = editor.detectMarkupInRange(range, 'a'); - - if (hasLink) { - editor.run(postEditor => postEditor.toggleMarkup('a')); - } else { - editor.showPrompt('Enter a URL', defaultUrl, url => { - if (!url) { return; } - - editor.run(postEditor => { - let markup = postEditor.builder.createMarkup('a', {href: url}); - postEditor.toggleMarkup(markup); - }); - }); - } - } }, { str: 'META+Z', run(editor) { diff --git a/tests/acceptance/editor-key-commands-test.js b/tests/acceptance/editor-key-commands-test.js index 601512592..3c8550d9f 100644 --- a/tests/acceptance/editor-key-commands-test.js +++ b/tests/acceptance/editor-key-commands-test.js @@ -2,8 +2,9 @@ import { MODIFIERS } from 'mobiledoc-kit/utils/key'; import Keycodes from 'mobiledoc-kit/utils/keycodes'; import Helpers from '../test-helpers'; import Range from 'mobiledoc-kit/utils/cursor/range'; +import Browser from 'mobiledoc-kit/utils/browser'; -const { module, test } = Helpers; +const { module, test, skip } = Helpers; let editor, editorElement; @@ -152,57 +153,59 @@ testStatefulCommand({ markupName: 'em' }); -test(`ctrl-k clears to the end of a line`, (assert) => { - let initialText = 'something'; - editor = renderIntoAndFocusTail(({post, markupSection, marker}) => post([ - markupSection('p', [marker(initialText)]) - ])); +if (Browser.isMac()) { + test(`[Mac] ctrl-k clears to the end of a line`, (assert) => { + let initialText = 'something'; + editor = renderIntoAndFocusTail(({post, markupSection, marker}) => post([ + markupSection('p', [marker(initialText)]) + ])); - assert.ok(editor.hasCursor(), 'has cursor'); + assert.ok(editor.hasCursor(), 'has cursor'); - let textElement = editor.post.sections.head.markers.head.renderNode.element; - Helpers.dom.moveCursorTo(editor, textElement, 4); - Helpers.dom.triggerKeyCommand(editor, 'K', MODIFIERS.CTRL); - - let changedMobiledoc = editor.serialize(); - let expectedMobiledoc = Helpers.mobiledoc.build( - ({post, markupSection, marker}) => { - return post([ - markupSection('p', [ - marker('some') - ]) - ]); + let textElement = editor.post.sections.head.markers.head.renderNode.element; + Helpers.dom.moveCursorTo(editor, textElement, 4); + Helpers.dom.triggerKeyCommand(editor, 'K', MODIFIERS.CTRL); + + let changedMobiledoc = editor.serialize(); + let expectedMobiledoc = Helpers.mobiledoc.build( + ({post, markupSection, marker}) => { + return post([ + markupSection('p', [ + marker('some') + ]) + ]); + }); + assert.deepEqual(changedMobiledoc, expectedMobiledoc, + 'mobiledoc updated appropriately'); }); - assert.deepEqual(changedMobiledoc, expectedMobiledoc, - 'mobiledoc updated appropriately'); -}); -test(`ctrl-k clears selected text`, (assert) => { - let initialText = 'something'; - editor = renderIntoAndFocusTail( ({post, markupSection, marker}) => post([ - markupSection('p', [marker(initialText)]) - ])); + test(`[Mac] ctrl-k clears selected text`, (assert) => { + let initialText = 'something'; + editor = renderIntoAndFocusTail( ({post, markupSection, marker}) => post([ + markupSection('p', [marker(initialText)]) + ])); - assert.ok(editor.hasCursor(), 'has cursor'); + assert.ok(editor.hasCursor(), 'has cursor'); - let textElement = editor.post.sections.head.markers.head.renderNode.element; - Helpers.dom.moveCursorTo(editor, textElement, 4, textElement, 8); - Helpers.dom.triggerKeyCommand(editor, 'K', MODIFIERS.CTRL); - - let changedMobiledoc = editor.serialize(); - let expectedMobiledoc = Helpers.mobiledoc.build( - ({post, markupSection, marker}) => { - return post([ - markupSection('p', [ - marker('someg') - ]) - ]); + let textElement = editor.post.sections.head.markers.head.renderNode.element; + Helpers.dom.moveCursorTo(editor, textElement, 4, textElement, 8); + Helpers.dom.triggerKeyCommand(editor, 'K', MODIFIERS.CTRL); + + let changedMobiledoc = editor.serialize(); + let expectedMobiledoc = Helpers.mobiledoc.build( + ({post, markupSection, marker}) => { + return post([ + markupSection('p', [ + marker('someg') + ]) + ]); + }); + assert.deepEqual(changedMobiledoc, expectedMobiledoc, + 'mobiledoc updated appropriately'); }); - assert.deepEqual(changedMobiledoc, expectedMobiledoc, - 'mobiledoc updated appropriately'); -}); +} -test('cmd-k links selected text', (assert) => { +let toggleLinkTest = (assert, modifier) => { assert.expect(3); let url = 'http://bustle.com'; @@ -218,12 +221,12 @@ test('cmd-k links selected text', (assert) => { }; Helpers.dom.selectText(editor ,'something', editorElement); - Helpers.dom.triggerKeyCommand(editor, 'K', MODIFIERS.META); + Helpers.dom.triggerKeyCommand(editor, 'K', modifier); assert.hasElement(`#editor a[href="${url}"]:contains(something)`); -}); +}; -test('cmd-k unlinks selected text if it was already linked', (assert) => { +let toggleLinkUnlinkTest = (assert, modifier) => { assert.expect(4); let url = 'http://bustle.com'; @@ -240,11 +243,48 @@ test('cmd-k unlinks selected text if it was already linked', (assert) => { 'precond -- has link'); Helpers.dom.selectText(editor ,'something', editorElement); - Helpers.dom.triggerKeyCommand(editor, 'K', MODIFIERS.META); + Helpers.dom.triggerKeyCommand(editor, 'K', modifier); assert.hasNoElement(`#editor a[href="${url}"]:contains(something)`, 'removes linked text'); assert.hasElement(`#editor p:contains(something)`, 'unlinked text remains'); +}; + +let toggleTests = [ + { + precondition: () => Browser.isMac(), + msg: '[Mac] cmd-k links selected text', + testFn: toggleLinkTest, + modifier: MODIFIERS.META + }, + { + precondition: () => Browser.isMac(), + msg: '[Mac] cmd-k unlinks selected text if it was already linked', + testFn: toggleLinkUnlinkTest, + modifier: MODIFIERS.META + }, + { + precondition: () => Browser.isWin(), + msg: '[Windows] ctrl-k links selected text', + testFn: toggleLinkTest, + modifier: MODIFIERS.CTRL + }, + { + precondition: () => Browser.isWin(), + msg: '[Windows] ctrl-k unlinks selected text if it was already linked', + testFn: toggleLinkUnlinkTest, + modifier: MODIFIERS.CTRL + }, +]; + +toggleTests.forEach(({precondition, msg, testFn, modifier}) => { + if (!precondition()) { + skip(msg); + } else { + test(msg, (assert) => { + testFn(assert, modifier); + }); + } }); test('new key commands can be registered', (assert) => { diff --git a/tests/test-helpers.js b/tests/test-helpers.js index 5ea3918c2..b8d8962d7 100644 --- a/tests/test-helpers.js +++ b/tests/test-helpers.js @@ -48,6 +48,7 @@ export default { test, module, skipInIE11, + skip, wait, postEditor: { run, renderBuiltAbstract, MockEditor } };