Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 44 additions & 31 deletions src/js/editor/key-commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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',
Expand Down Expand Up @@ -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) {
Expand Down
136 changes: 88 additions & 48 deletions tests/acceptance/editor-key-commands-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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';
Expand All @@ -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';
Expand All @@ -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) => {
Expand Down
1 change: 1 addition & 0 deletions tests/test-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export default {
test,
module,
skipInIE11,
skip,
wait,
postEditor: { run, renderBuiltAbstract, MockEditor }
};