Repository: withspectrum/draft-js-markdown-plugin (js)

Issue:
replace ``` when exiting a code block
When closing a codeblock, hitting enter with this state:

````
[CODE]
last line of codeblock```[CURSOR]
[/CODE]
````

produces this state
````
[CODE]
last line of codeblock```
[/CODE]
[CURSOR]
````

when it should really remove the backticks like so

````
[CODE]
last line of codeblock
[/CODE]
[CURSOR]
````

Note: This only happens when the last line is not empty (when empty the backticks get removed)

Pull request description:
Fix code block exit with ```
properly replaces backticks on both empty and non-empty lines

fixes #51 

Patch:
diff --git a/src/index.js b/src/index.js
index 77e5773..4b5477a 100755
--- a/src/index.js
+++ b/src/index.js
@@ -18,6 +18,7 @@ import {
 import adjustBlockDepth from "./modifiers/adjustBlockDepth";
 import handleBlockType from "./modifiers/handleBlockType";
 import handleInlineStyle from "./modifiers/handleInlineStyle";
+import splitBlockAndChange from "./modifiers/splitBlockAndChange";
 import handleNewCodeBlock from "./modifiers/handleNewCodeBlock";
 import resetInlineStyle from "./modifiers/resetInlineStyle";
 import insertEmptyBlock from "./modifiers/insertEmptyBlock";
@@ -134,11 +135,14 @@ function checkReturnForState(config, editorState, ev) {
     newEditorState = leaveList(editorState);
   }
 
+  const isHeader = /^header-/.test(type);
+  const isBlockQuote = type === "blockquote";
+
   const modifierKeyPressed =
     ev.ctrlKey || ev.shiftKey || ev.metaKey || ev.altKey;
   const isAtEndOfLine = endOffset === blockLength;
-  const atEndOfHeader = /^header-/.test(type) && isAtEndOfLine;
-  const atEndOfBlockQuote = type === "blockquote" && isAtEndOfLine;
+  const atEndOfHeader = isHeader && isAtEndOfLine;
+  const atEndOfBlockQuote = isBlockQuote && isAtEndOfLine;
 
   if (
     newEditorState === editorState &&
@@ -154,6 +158,8 @@ function checkReturnForState(config, editorState, ev) {
     } else {
       newEditorState = RichUtils.toggleBlockType(newEditorState, type);
     }
+  } else if (isCollapsed && (isHeader || isBlockQuote) && !isAtEndOfLine) {
+    newEditorState = splitBlockAndChange(newEditorState);
   }
   if (
     newEditorState === editorState &&
@@ -168,7 +174,7 @@ function checkReturnForState(config, editorState, ev) {
       newEditorState = changeCurrentBlockType(
         newEditorState,
         type,
-        text.replace(/\n```\s*$/, "")
+        text.replace(/```\s*$/, "")
       );
       newEditorState = insertEmptyBlock(newEditorState);
     } else {
@@ -296,7 +302,7 @@ const createMarkdownPlugin = (_config = {}) => {
 
       newEditorState = resetInlineStyle(newEditorState);
 
-      if (!is(editorState.getImmutable(), newEditorState.getImmutable())) {
+      if (editorState !== newEditorState) {
         setEditorState(
           EditorState.push(newEditorState, content, "split-block")
         );
diff --git a/src/modifiers/splitBlockAndChange.js b/src/modifiers/splitBlockAndChange.js
new file mode 100644
index 0000000..3878979
--- /dev/null
+++ b/src/modifiers/splitBlockAndChange.js
@@ -0,0 +1,25 @@
+import { EditorState, Modifier } from "draft-js";
+
+const splitBlockAndChange = (
+  editorState,
+  type = "unstyled",
+  blockMetadata = {}
+) => {
+  let currentContent = editorState.getCurrentContent();
+  let selection = editorState.getSelection();
+  currentContent = Modifier.splitBlock(currentContent, selection);
+  selection = currentContent.getSelectionAfter();
+  const key = selection.getStartKey();
+  const blockMap = currentContent.getBlockMap();
+  const block = blockMap.get(key);
+  const data = block.getData().merge(blockMetadata);
+  const newBlock = block.merge({ type, data });
+  const newContentState = currentContent.merge({
+    blockMap: blockMap.set(key, newBlock),
+    selectionAfter: selection,
+  });
+
+  return EditorState.push(editorState, newContentState, "split-block");
+};
+
+export default splitBlockAndChange;


Test patch:
diff --git a/src/__test__/plugin.test.js b/src/__test__/plugin.test.js
index dd32ee3..eac9823 100755
--- a/src/__test__/plugin.test.js
+++ b/src/__test__/plugin.test.js
@@ -17,6 +17,7 @@ describe("draft-js-markdown-plugin", () => {
     createMarkdownPlugin.__ResetDependency__("handleInlineStyle");
     createMarkdownPlugin.__ResetDependency__("handleNewCodeBlock");
     createMarkdownPlugin.__ResetDependency__("insertEmptyBlock");
+    createMarkdownPlugin.__ResetDependency__("splitBlockAndChange");
     createMarkdownPlugin.__ResetDependency__("handleLink");
     createMarkdownPlugin.__ResetDependency__("handleImage");
     createMarkdownPlugin.__ResetDependency__("leaveList");
@@ -268,7 +269,10 @@ describe("draft-js-markdown-plugin", () => {
           describe(`on ${type}`, () => {
             const text = "Hello";
             beforeEach(() => {
-              createMarkdownPlugin.__Rewire__("insertEmptyBlock", modifierSpy); // eslint-disable-line no-underscore-dangle
+              createMarkdownPlugin.__Rewire__(
+                "splitBlockAndChange",
+                modifierSpy
+              ); // eslint-disable-line no-underscore-dangle
               currentRawContentState = {
                 entityMap: {},
                 blocks: [
@@ -287,6 +291,10 @@ describe("draft-js-markdown-plugin", () => {
 
             describe("at the end of line", () => {
               beforeEach(() => {
+                createMarkdownPlugin.__Rewire__(
+                  "insertEmptyBlock",
+                  modifierSpy
+                ); // eslint-disable-line no-underscore-dangle
                 currentSelectionState = currentEditorState
                   .getSelection()
                   .merge({
@@ -308,14 +316,15 @@ describe("draft-js-markdown-plugin", () => {
               });
             });
             describe("when not at the end of the line", () => {
-              it("does not handle", () => {
-                expect(subject()).toBe("not-handled");
-                expect(modifierSpy).not.toHaveBeenCalled();
-                expect(store.setEditorState).not.toHaveBeenCalled();
+              it("splits and resets block", () => {
+                expect(subject()).toBe("handled");
+                expect(modifierSpy).toHaveBeenCalled();
+                expect(store.setEditorState).toHaveBeenCalled();
               });
             });
           });
         });
+
         ["ctrlKey", "shiftKey", "metaKey", "altKey"].forEach(key => {
           describe(`${key} is pressed`, () => {
             beforeEach(() => {