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

Commit

Permalink
Merge pull request #43 from withspectrum/whitelist-features
Browse files Browse the repository at this point in the history
Whitelist markdown features via `config.features`
  • Loading branch information
mxstbr authored Apr 6, 2018
2 parents 7002ed8 + 4b7a56d commit 6322893
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 68 deletions.
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,64 @@ const languages = {
const markdownPlugin = createMarkdownPlugin({ languages })
```

### `features`
A list of enabled features, by default all features are turned on.

```js
features = {
block: Array<string>,
inline: Array<string>,
}
```

````
#### Example
```
// this will only enable BOLD for inline and CODE
// as well as header-one for blocks
const features = {
inline: ['BOLD'],
block: ['CODE', 'header-one'],
}
const plugin = createMarkdownPlugin({ features })
```
*Available Inline features*:
```js
[
'BOLD',
'ITALIC',
'CODE',
'STRIKETHROUGH',
'LINK',
'IMAGE'
]
```
*Available Block features*:
```js
import { CHECKABLE_LIST_ITEM } from "draft-js-checkable-list-item"
[
'CODE',
'header-one',
'header-two',
'header-three',
'header-four',
'header-five',
'header-six',
'ordered-list-item',
'unordered-list-item',
// CHECKABLE_LIST_ITEM is a constant from 'draft-js-checkable-list-item'
// see import statementabove
CHECKABLE_LIST_ITEM,
'blockquote',
]
```
## Usage
```js
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@
"peerDependencies": {
"draft-js-plugins-editor": "~2.0.0-rc.1 || 2.0.0-rc2 || 2.0.0-rc1 || 2.0.0-beta12",
"react": "^15.0.0",
"react-dom": "^15.0.0",
"react-portal": "^4.1.4"
"react-dom": "^15.0.0"
},
"contributors": [
"Atsushi Nagase <a@ngs.io>"
Expand Down
39 changes: 33 additions & 6 deletions src/__test__/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
CheckableListItemUtils,
} from "draft-js-checkable-list-item";

import { defaultInlineWhitelist, defaultBlockWhitelist } from "../constants";

import { Map, List } from "immutable";
import createMarkdownPlugin from "../";

Expand Down Expand Up @@ -451,12 +453,7 @@ describe("draft-js-markdown-plugin", () => {
],
};
});
[
"handleBlockType",
"handleImage",
"handleLink",
"handleInlineStyle",
].forEach(modifier => {
["handleImage", "handleLink"].forEach(modifier => {
describe(modifier, () => {
beforeEach(() => {
createMarkdownPlugin.__Rewire__(modifier, modifierSpy); // eslint-disable-line no-underscore-dangle
Expand All @@ -467,6 +464,36 @@ describe("draft-js-markdown-plugin", () => {
});
});
});
["handleBlockType"].forEach(modifier => {
describe(modifier, () => {
beforeEach(() => {
createMarkdownPlugin.__Rewire__(modifier, modifierSpy); // eslint-disable-line no-underscore-dangle
});
it("returns handled", () => {
expect(subject()).toBe("handled");
expect(modifierSpy).toHaveBeenCalledWith(
defaultBlockWhitelist,
currentEditorState,
" "
);
});
});
});
["handleInlineStyle"].forEach(modifier => {
describe(modifier, () => {
beforeEach(() => {
createMarkdownPlugin.__Rewire__(modifier, modifierSpy); // eslint-disable-line no-underscore-dangle
});
it("returns handled", () => {
expect(subject()).toBe("handled");
expect(modifierSpy).toHaveBeenCalledWith(
defaultInlineWhitelist,
currentEditorState,
" "
);
});
});
});
describe("character is not a space", () => {
beforeEach(() => {
character = "x";
Expand Down
25 changes: 25 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CHECKABLE_LIST_ITEM } from "draft-js-checkable-list-item";

export const CODE_BLOCK_REGEX = /^```([\w-]+)?\s*$/;

export const inlineMatchers = {
Expand All @@ -8,3 +10,26 @@ export const inlineMatchers = {
};

export const CODE_BLOCK_TYPE = "code-block";

export const defaultInlineWhitelist = [
"BOLD",
"ITALIC",
"CODE",
"STRIKETHROUGH",
"LINK",
"IMAGE",
];

export const defaultBlockWhitelist = [
"CODE",
"header-one",
"header-two",
"header-three",
"header-four",
"header-five",
"header-six",
"ordered-list-item",
"unordered-list-item",
CHECKABLE_LIST_ITEM,
"blockquote",
];
66 changes: 53 additions & 13 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ import changeCurrentBlockType from "./modifiers/changeCurrentBlockType";
import createLinkDecorator from "./decorators/link";
import createImageDecorator from "./decorators/image";
import { replaceText } from "./utils";
import { CODE_BLOCK_REGEX, CODE_BLOCK_TYPE } from "./constants";
import {
CODE_BLOCK_REGEX,
CODE_BLOCK_TYPE,
defaultInlineWhitelist,
defaultBlockWhitelist,
} from "./constants";

const defaultLanguages = {
bash: "Bash",
Expand Down Expand Up @@ -85,21 +90,35 @@ function inCodeBlock(editorState) {
return false;
}

function checkCharacterForState(editorState, character) {
let newEditorState = handleBlockType(editorState, character);
if (editorState === newEditorState) {
function checkCharacterForState(config, editorState, character) {
let newEditorState = handleBlockType(
config.features.block,
editorState,
character
);
if (
editorState === newEditorState &&
config.features.inline.includes("IMAGE")
) {
newEditorState = handleImage(editorState, character);
}
if (editorState === newEditorState) {
if (
editorState === newEditorState &&
config.features.inline.includes("LINK")
) {
newEditorState = handleLink(editorState, character);
}
if (editorState === newEditorState) {
newEditorState = handleInlineStyle(editorState, character);
newEditorState = handleInlineStyle(
config.features.inline,
editorState,
character
);
}
return newEditorState;
}

function checkReturnForState(editorState, ev) {
function checkReturnForState(config, editorState, ev) {
let newEditorState = editorState;
const contentState = editorState.getCurrentContent();
const selection = editorState.getSelection();
Expand All @@ -123,7 +142,7 @@ function checkReturnForState(editorState, ev) {
) {
// transform markdown (if we aren't in a codeblock that is)
if (!inCodeBlock(editorState)) {
newEditorState = checkCharacterForState(newEditorState, "\n");
newEditorState = checkCharacterForState(config, newEditorState, "\n");
}
if (newEditorState === editorState) {
newEditorState = insertEmptyBlock(newEditorState);
Expand All @@ -134,6 +153,7 @@ function checkReturnForState(editorState, ev) {
if (
newEditorState === editorState &&
type !== "code-block" &&
config.features.block.includes("CODE") &&
CODE_BLOCK_REGEX.test(text)
) {
newEditorState = handleNewCodeBlock(editorState);
Expand All @@ -157,6 +177,10 @@ function checkReturnForState(editorState, ev) {
const defaultConfig = {
renderLanguageSelect: defaultRenderSelect,
languages: defaultLanguages,
features: {
inline: defaultInlineWhitelist,
block: defaultBlockWhitelist,
},
};

const createMarkdownPlugin = (_config = {}) => {
Expand All @@ -165,6 +189,10 @@ const createMarkdownPlugin = (_config = {}) => {
const config = {
...defaultConfig,
..._config,
features: {
...defaultConfig.features,
..._config.features,
},
};

return {
Expand Down Expand Up @@ -237,7 +265,7 @@ const createMarkdownPlugin = (_config = {}) => {
handleReturn(ev, editorState, { setEditorState }) {
if (inLink(editorState)) return "not-handled";

let newEditorState = checkReturnForState(editorState, ev);
let newEditorState = checkReturnForState(config, editorState, ev);
const selection = newEditorState.getSelection();

// exit code blocks
Expand All @@ -249,7 +277,7 @@ const createMarkdownPlugin = (_config = {}) => {
return "handled";
}

newEditorState = checkCharacterForState(newEditorState, "\n");
newEditorState = checkCharacterForState(config, newEditorState, "\n");
let content = newEditorState.getCurrentContent();

// if there are actually no changes but the editorState has a
Expand Down Expand Up @@ -283,7 +311,11 @@ const createMarkdownPlugin = (_config = {}) => {
// If we're in a link - don't transform markdown
if (inLink(editorState)) return "not-handled";

const newEditorState = checkCharacterForState(editorState, character);
const newEditorState = checkCharacterForState(
config,
editorState,
character
);
if (editorState !== newEditorState) {
setEditorState(newEditorState);
return "handled";
Expand Down Expand Up @@ -334,11 +366,19 @@ const createMarkdownPlugin = (_config = {}) => {
newEditorState,
buffer.join("") + text[i]
);
newEditorState = checkCharacterForState(newEditorState, text[i]);
newEditorState = checkCharacterForState(
config,
newEditorState,
text[i]
);
buffer = [];
} else if (text[i].charCodeAt(0) === 10) {
newEditorState = replaceText(newEditorState, buffer.join(""));
const tmpEditorState = checkReturnForState(newEditorState, {});
const tmpEditorState = checkReturnForState(
config,
newEditorState,
{}
);
if (newEditorState === tmpEditorState) {
newEditorState = insertEmptyBlock(tmpEditorState);
} else {
Expand Down
19 changes: 16 additions & 3 deletions src/modifiers/__test__/handleBlockType-test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Draft, { EditorState, SelectionState } from "draft-js";
import handleBlockType from "../handleBlockType";
import { defaultBlockWhitelist } from "../../constants";

describe("handleBlockType", () => {
describe("no markup", () => {
Expand Down Expand Up @@ -31,7 +32,11 @@ describe("handleBlockType", () => {
selection
);
it("does not convert block type", () => {
const newEditorState = handleBlockType(editorState, " ");
const newEditorState = handleBlockType(
defaultBlockWhitelist,
editorState,
" "
);
expect(newEditorState).toEqual(editorState);
expect(Draft.convertToRaw(newEditorState.getCurrentContent())).toEqual(
rawContentState
Expand Down Expand Up @@ -69,7 +74,11 @@ describe("handleBlockType", () => {
);

it("does not convert block type", () => {
const newEditorState = handleBlockType(editorState, " ");
const newEditorState = handleBlockType(
defaultBlockWhitelist,
editorState,
" "
);
expect(newEditorState).toEqual(editorState);
expect(Draft.convertToRaw(newEditorState.getCurrentContent())).toEqual(
rawContentState
Expand Down Expand Up @@ -549,7 +558,11 @@ describe("handleBlockType", () => {
selection
);
it("converts block type", () => {
const newEditorState = handleBlockType(editorState, character);
const newEditorState = handleBlockType(
defaultBlockWhitelist,
editorState,
character
);
expect(newEditorState).not.toEqual(editorState);
expect(Draft.convertToRaw(newEditorState.getCurrentContent())).toEqual(
after
Expand Down
Loading

0 comments on commit 6322893

Please sign in to comment.