Skip to content
This repository was archived by the owner on Oct 11, 2022. It is now read-only.

Commit c9a9d7a

Browse files
committed
Merge branch 'master' of github.com:withspectrum/draft-js-markdown-plugin into apply-transform-only-when-cursor-at-end-of-delimiter
2 parents b785d18 + 6ce7a20 commit c9a9d7a

File tree

5 files changed

+130
-24
lines changed

5 files changed

+130
-24
lines changed

src/__test__/plugin.test.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import sinon from "sinon";
21
import Draft, { EditorState, SelectionState, ContentBlock } from "draft-js";
32
import {
43
CheckableListItem,
@@ -99,10 +98,12 @@ describe("draft-js-markdown-plugin", () => {
9998
it("is loaded", () => {
10099
expect(typeof createMarkdownPlugin).toBe("function");
101100
});
101+
102102
it("initialize", () => {
103103
plugin.initialize(store);
104104
expect(plugin.store).toEqual(store);
105105
});
106+
106107
describe("handleReturn", () => {
107108
beforeEach(() => {
108109
subject = () =>
@@ -127,6 +128,33 @@ describe("draft-js-markdown-plugin", () => {
127128
expect(modifierSpy).not.toHaveBeenCalledTimes(1);
128129
expect(store.setEditorState).not.toHaveBeenCalled();
129130
});
131+
132+
it("resets curent inline style", () => {
133+
currentRawContentState = {
134+
entityMap: {},
135+
blocks: [
136+
{
137+
key: "item1",
138+
text: "item1",
139+
type: "unstyled",
140+
depth: 0,
141+
inlineStyleRanges: [{ offset: 0, length: 5, style: "BOLD" }],
142+
entityRanges: [],
143+
data: {},
144+
},
145+
],
146+
};
147+
currentSelectionState = currentSelectionState.merge({
148+
focusOffset: 5,
149+
anchorOffset: 5,
150+
});
151+
152+
expect(subject()).toBe("handled");
153+
expect(store.setEditorState).toHaveBeenCalled();
154+
newEditorState = store.setEditorState.mock.calls[0][0];
155+
expect(newEditorState.getCurrentInlineStyle().size).toBe(0);
156+
});
157+
130158
it("leaves from list", () => {
131159
createMarkdownPlugin.__Rewire__("leaveList", modifierSpy); // eslint-disable-line no-underscore-dangle
132160
currentRawContentState = {
@@ -147,6 +175,38 @@ describe("draft-js-markdown-plugin", () => {
147175
expect(modifierSpy).toHaveBeenCalledTimes(1);
148176
expect(store.setEditorState).toHaveBeenCalledWith(newEditorState);
149177
});
178+
179+
it("adds list item and transforms markdown", () => {
180+
// createMarkdownPlugin.__Rewire__("leaveList", modifierSpy); // eslint-disable-line no-underscore-dangle
181+
currentRawContentState = {
182+
entityMap: {},
183+
blocks: [
184+
{
185+
key: "item1",
186+
text: "**some bold text**",
187+
type: "unordered-list-item",
188+
depth: 0,
189+
inlineStyleRanges: [],
190+
entityRanges: [],
191+
data: {},
192+
},
193+
],
194+
};
195+
currentSelectionState = currentSelectionState.merge({
196+
focusOffset: 18,
197+
anchorOffset: 18,
198+
});
199+
expect(subject()).toBe("handled");
200+
// expect(modifierSpy).toHaveBeenCalledTimes(1);
201+
expect(store.setEditorState).toHaveBeenCalledTimes(1);
202+
newEditorState = store.setEditorState.mock.calls[0][0];
203+
const newRawContentState = Draft.convertToRaw(
204+
newEditorState.getCurrentContent()
205+
);
206+
expect(newRawContentState.blocks.length).toBe(2);
207+
expect(newEditorState.getCurrentInlineStyle().size).toBe(0);
208+
});
209+
150210
const testInsertNewBlock = type => () => {
151211
createMarkdownPlugin.__Rewire__("insertEmptyBlock", modifierSpy); // eslint-disable-line no-underscore-dangle
152212
currentRawContentState = {

src/index.js

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ import {
66
CHECKABLE_LIST_ITEM,
77
} from "draft-js-checkable-list-item";
88

9-
import { Map } from "immutable";
10-
9+
import { Map, OrderedSet, is } from "immutable";
10+
import {
11+
getDefaultKeyBinding,
12+
Modifier,
13+
EditorState,
14+
RichUtils,
15+
DefaultDraftInlineStyle,
16+
} from "draft-js";
1117
import adjustBlockDepth from "./modifiers/adjustBlockDepth";
1218
import handleBlockType from "./modifiers/handleBlockType";
1319
import handleInlineStyle from "./modifiers/handleInlineStyle";
1420
import handleNewCodeBlock from "./modifiers/handleNewCodeBlock";
21+
import resetInlineStyle from "./modifiers/resetInlineStyle";
1522
import insertEmptyBlock from "./modifiers/insertEmptyBlock";
1623
import handleLink from "./modifiers/handleLink";
1724
import handleImage from "./modifiers/handleImage";
@@ -60,9 +67,11 @@ function checkReturnForState(editorState, ev) {
6067
const currentBlock = contentState.getBlockForKey(key);
6168
const type = currentBlock.getType();
6269
const text = currentBlock.getText();
70+
6371
if (/-list-item$/.test(type) && text === "") {
6472
newEditorState = leaveList(editorState);
6573
}
74+
6675
if (
6776
newEditorState === editorState &&
6877
(ev.ctrlKey ||
@@ -72,7 +81,15 @@ function checkReturnForState(editorState, ev) {
7281
/^header-/.test(type) ||
7382
type === "blockquote")
7483
) {
75-
newEditorState = insertEmptyBlock(editorState);
84+
// transform markdown (if we aren't in a codeblock that is)
85+
if (!inCodeBlock(editorState)) {
86+
newEditorState = checkCharacterForState(newEditorState, "\n");
87+
}
88+
if (newEditorState === editorState) {
89+
newEditorState = insertEmptyBlock(newEditorState);
90+
} else {
91+
newEditorState = RichUtils.toggleBlockType(newEditorState, type);
92+
}
7693
}
7794
if (
7895
newEditorState === editorState &&
@@ -154,17 +171,35 @@ const createMarkdownPlugin = (config = {}) => {
154171
},
155172
handleReturn(ev, editorState, { setEditorState }) {
156173
let newEditorState = checkReturnForState(editorState, ev);
157-
if (editorState !== newEditorState) {
174+
let selection = newEditorState.getSelection();
175+
176+
// exit code blocks
177+
if (
178+
inCodeBlock(editorState) &&
179+
!is(editorState.getImmutable(), newEditorState.getImmutable())
180+
) {
158181
setEditorState(newEditorState);
159182
return "handled";
160183
}
161184

162-
// If we're in a code block don't add markdown to it
163-
if (inCodeBlock(editorState)) return "not-handled";
185+
newEditorState = checkCharacterForState(newEditorState, "\n");
186+
let content = newEditorState.getCurrentContent();
164187

165-
newEditorState = checkCharacterForState(editorState, "\n");
166-
if (editorState !== newEditorState) {
167-
setEditorState(newEditorState);
188+
// if there are actually no changes but the editorState has a
189+
// current inline style we want to split the block
190+
if (
191+
is(editorState.getImmutable(), newEditorState.getImmutable()) &&
192+
editorState.getCurrentInlineStyle().size > 0
193+
) {
194+
content = Modifier.splitBlock(content, selection);
195+
}
196+
197+
newEditorState = resetInlineStyle(newEditorState);
198+
199+
if (!is(editorState.getImmutable(), newEditorState.getImmutable())) {
200+
setEditorState(
201+
EditorState.push(newEditorState, content, "split-block")
202+
);
168203
return "handled";
169204
}
170205

src/modifiers/__test__/changeCurrentInlineStyle-test.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,12 @@ describe("changeCurrentInlineStyle", () => {
7070
"\n"
7171
);
7272
expect(newEditorState).not.toEqual(editorState);
73-
expect(Draft.convertToRaw(newEditorState.getCurrentContent())).toEqual(
74-
rawContentState(
75-
"foo bar\n baz",
76-
[
77-
{
78-
length: 3,
79-
offset: 4,
80-
style: "CODE",
81-
},
82-
],
83-
"CODE"
84-
)
85-
);
73+
const contentState = Draft.convertToRaw(newEditorState.getCurrentContent());
74+
expect(contentState.blocks.length).toBe(2);
75+
expect(contentState.blocks[0].text).toEqual("foo bar");
76+
expect(contentState.blocks[0].inlineStyleRanges).toEqual([
77+
{ offset: 4, length: 3, style: "CODE" },
78+
]);
79+
expect(contentState.blocks[1].text).toEqual(" baz");
8680
});
8781
});

src/modifiers/changeCurrentInlineStyle.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,18 @@ const changeCurrentInlineStyle = (editorState, matchArr, style, character) => {
2121

2222
let newContentState = currentContent;
2323

24+
// if appendChar isn't defined add a space
25+
// if character is a newline - add empty string and later on - split block
26+
let appendChar = character == null ? " " : character;
27+
if (character == "\n") appendChar = "";
28+
2429
// remove markdown delimiter at end
2530
newContentState = Modifier.replaceText(
2631
newContentState,
2732
wordSelection.merge({
2833
anchorOffset: wordSelection.getFocusOffset() - markdownCharacterLength,
2934
}),
30-
character || " "
35+
appendChar
3136
);
3237

3338
let afterSelection = newContentState.getSelectionAfter();
@@ -56,6 +61,11 @@ const changeCurrentInlineStyle = (editorState, matchArr, style, character) => {
5661
style
5762
);
5863

64+
if (character == "\n") {
65+
newContentState = Modifier.splitBlock(newContentState, afterSelection);
66+
afterSelection = newContentState.getSelectionAfter();
67+
}
68+
5969
const newEditorState = EditorState.push(
6070
editorState,
6171
newContentState,

src/modifiers/resetInlineStyle.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { OrderedSet } from "immutable";
2+
import { EditorState } from "draft-js";
3+
4+
export default editorState =>
5+
editorState.getCurrentInlineStyle().size === 0
6+
? editorState
7+
: EditorState.setInlineStyleOverride(editorState, OrderedSet());

0 commit comments

Comments
 (0)