diff --git a/.eslintrc b/.eslintrc
index 3f8f97d..59ba29e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,16 +1,16 @@
{
- extends: [
+ "extends": [
"standard",
],
- rules: {
+ "rules": {
"comma-dangle": [2, "always-multiline"]
},
- parserOptions: {
- ecmaVersion: 6,
- sourceType: "module",
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module"
},
- plugins: [
- "standard",
+ "plugins": [
+ "standard"
]
}
diff --git a/.gitignore b/.gitignore
index 66fd66c..d892955 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
node_modules
npm-debug.log*
+dist
diff --git a/README.md b/README.md
index 6fa8412..9e05d35 100644
--- a/README.md
+++ b/README.md
@@ -36,12 +36,28 @@ You can pass options to the plugin as you call it:
```js
const options = {
- stripEntities: false
+ stripEntities: false,
+ stripNewlines: false,
}
const singleLinePlugin = createSingleLinePlugin(options)
```
-There’s only one option so far: `stripEntities: true/false`.
+### stripEntities
+
+Strip Entities from text.
+
+Type: `boolean`
+Default: `true`
+Options: `true` | `false`
+
+### stripNewlines
+
+Strip newline characters `\n` from text.
+
+Type: `boolean`
+Default: `true`
+Options: `true` | `false`
+
## Developing
diff --git a/lib/index.js b/lib/index.js
deleted file mode 100644
index 7c66fb5..0000000
--- a/lib/index.js
+++ /dev/null
@@ -1,112 +0,0 @@
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _immutable = require('immutable');
-
-var _draftJs = require('draft-js');
-
-var _utils = require('./utils');
-
-/**
- * Default options
- * @type {Object}
- */
-var defaultOptions = {
- stripEntities: true
-};
-
-/**
- * Single Line Plugin
- * @param {Object} options Per-instance options to override the defaults
- * @return {Object} Compatible draft-js-editor-plugin object
- */
-function singleLinePlugin() {
- var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
-
- options = Object.assign({}, defaultOptions, options);
-
- return {
- /**
- * Return a compatible blockRenderMap
- *
- * NOTE: Needs to be explicitly applied, the plugin system doesn’t do
- * anything with this at the moment.
- *
- * @type {ImmutableMap}
- */
- blockRenderMap: (0, _immutable.Map)({
- 'unstyled': {
- element: 'div'
- }
- }),
-
- /**
- * onChange
- *
- * Condense multiple blocks into a single block and (optionally) strip all
- * entities from the content of that block.
- *
- * @param {EditorState} editorState The current state of the editor
- * @return {EditorState} A new editor state
- */
- onChange: function onChange(editorState) {
- var blocks = editorState.getCurrentContent().getBlocksAsArray();
-
- // If we have more than one block, compress them
- if (blocks.length > 1) {
- editorState = (0, _utils.condenseBlocks)(editorState, blocks, options);
- } else {
- // We only have one content block
- var contentBlock = blocks[0];
- var text = contentBlock.getText();
- var characterList = contentBlock.getCharacterList();
-
- if (_utils.NEWLINE_REGEX.test(text) || (0, _utils.characterListhasEntities)(characterList)) {
- // Replace the text stripped of its newlines. Note that we replace
- // one '\n' with one ' ' so we don't need to modify the characterList
- text = (0, _utils.replaceNewlines)(text);
-
- // Strip entities?
- if (options.stripEntities) {
- characterList = characterList.map(_utils.stripEntityFromCharacterMetadata);
- }
-
- // Create a new content block based on the old one
- contentBlock = new _draftJs.ContentBlock({
- key: (0, _draftJs.genKey)(),
- text: text,
- type: 'unstyled',
- characterList: characterList,
- depth: 0
- });
-
- // Update the editor state with the compressed version
- // const selection = editorState.getSelection()
- var newContentState = _draftJs.ContentState.createFromBlockArray([contentBlock]);
-
- // Create the new state as an undoable action
- editorState = _draftJs.EditorState.push(editorState, newContentState, 'insert-characters');
- editorState = _draftJs.EditorState.moveFocusToEnd(editorState);
- }
- }
-
- return editorState;
- },
-
-
- /**
- * Stop new lines being inserted by always handling the return
- *
- * @param {KeyboardEvent} e Synthetic keyboard event from draftjs
- * @return {Boolean} Did we handle the return or not? (pro-trip: yes, we did)
- */
- handleReturn: function handleReturn(e) {
- return true;
- }
- };
-}
-
-exports.default = singleLinePlugin;
\ No newline at end of file
diff --git a/lib/utils.js b/lib/utils.js
deleted file mode 100644
index 02ae41e..0000000
--- a/lib/utils.js
+++ /dev/null
@@ -1,99 +0,0 @@
-'use strict';
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-exports.NEWLINE_REGEX = undefined;
-exports.replaceNewlines = replaceNewlines;
-exports.condenseBlocks = condenseBlocks;
-exports.stripEntityFromCharacterMetadata = stripEntityFromCharacterMetadata;
-exports.characterListhasEntities = characterListhasEntities;
-
-var _draftJs = require('draft-js');
-
-var _immutable = require('immutable');
-
-/**
- * Greedy regex for matching newlines
- * @type {RegExp}
- */
-var NEWLINE_REGEX = exports.NEWLINE_REGEX = /\n/g;
-
-/**
- * Replace newline characters with the passed string
- * @param {String} str String to replace
- * @param {String} replacement Replacement characters
- * @return {String} Modified string
- */
-function replaceNewlines(str) {
- var replacement = arguments.length <= 1 || arguments[1] === undefined ? ' ' : arguments[1];
-
- return str.replace(NEWLINE_REGEX, replacement);
-}
-
-/**
- * Condense an array of content blocks into a single block
- * @param {EditorState} editorState draft-js EditorState instance
- * @param {Array} blocks Array of ContentBlocks
- * @param {Object} options
- * @return {EditorState} A modified EditorState instance
- */
-function condenseBlocks(editorState, blocks, options) {
- blocks = blocks || editorState.getCurrentContent().getBlocksAsArray();
- var text = (0, _immutable.List)();
- var characterList = (0, _immutable.List)();
-
- // Gather all the text/characterList and concat them
- blocks.forEach(function (block) {
- // Atomic blocks should be ignored (stripped)
- if (block.getType() !== 'atomic') {
- text = text.push(replaceNewlines(block.getText()));
- characterList = characterList.concat(block.getCharacterList());
- }
- });
-
- // Strip entities?
- if (options.stripEntities) {
- characterList = characterList.map(stripEntityFromCharacterMetadata);
- }
-
- // Create a new content block
- var contentBlock = new _draftJs.ContentBlock({
- key: (0, _draftJs.genKey)(),
- text: text.join(''),
- type: 'unstyled',
- characterList: characterList,
- depth: 0
- });
-
- // Update the editor state with the compressed version
- var newContentState = _draftJs.ContentState.createFromBlockArray([contentBlock]);
- // Create the new state as an undoable action
- editorState = _draftJs.EditorState.push(editorState, newContentState, 'remove-range');
- // Move the selection to the end
- return _draftJs.EditorState.moveFocusToEnd(editorState);
-}
-
-/**
- * Strip any `entity` keys from a CharacterMetadata set
- * @param {CharacterMetadata} characterMeta An Immutable.Record representing the metadata for an individual character
- * @return {CharacterMetadata}
- */
-function stripEntityFromCharacterMetadata(characterMeta) {
- return characterMeta.set('entity', null);
-}
-
-/**
- * Check if a CharacterList contains entities
- * @param {CharacterList} characterList The list of characters to check
- * @return {Boolean} Contains entities?
- */
-function characterListhasEntities(characterList) {
- var hasEntities = false;
- characterList.forEach(function (characterMeta) {
- if (characterMeta.get('entity') !== null) {
- hasEntities = true;
- }
- });
- return hasEntities;
-}
\ No newline at end of file
diff --git a/package.json b/package.json
index 325e412..210fa14 100644
--- a/package.json
+++ b/package.json
@@ -1,16 +1,15 @@
{
"name": "draft-js-single-line-plugin",
- "version": "0.0.1",
+ "version": "0.0.2",
"description": "Restrict a draft-js editor to a single line of input.",
- "main": "lib/index.js",
+ "main": "dist/index.js",
"scripts": {
- "build": "babel src --out-dir lib",
+ "build": "babel src --out-dir dist",
"compile": "npm run build",
"precompile": "npm run clean",
- "prepublish": "npm run compile",
"test": "NODE_ENV=test babel-node test | faucet",
"posttest": "npm run lint",
- "clean": "rm -rf ./lib/*",
+ "clean": "rm -rf ./dist/*",
"lint": "eslint 'src/*.js' 'src/**/*.js'; exit 0"
},
"repository": {
diff --git a/src/index.js b/src/index.js
index 89d98be..d7c6469 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,7 @@ import {
*/
const defaultOptions = {
stripEntities: true,
+ stripNewlines: true,
}
/**
@@ -65,11 +66,14 @@ function singleLinePlugin (options = {}) {
let contentBlock = blocks[0]
let text = contentBlock.getText()
let characterList = contentBlock.getCharacterList()
+ const isNewLine = (options.stripNewlines && NEWLINE_REGEX.test(text))
- if (NEWLINE_REGEX.test(text) || characterListhasEntities(characterList)) {
+ if (isNewLine || characterListhasEntities(characterList)) {
// Replace the text stripped of its newlines. Note that we replace
// one '\n' with one ' ' so we don't need to modify the characterList
- text = replaceNewlines(text)
+ if (options.stripNewlines) {
+ text = replaceNewlines(text)
+ }
// Strip entities?
if (options.stripEntities) {
@@ -86,7 +90,6 @@ function singleLinePlugin (options = {}) {
})
// Update the editor state with the compressed version
- // const selection = editorState.getSelection()
const newContentState = ContentState.createFromBlockArray([contentBlock])
// Create the new state as an undoable action
diff --git a/src/utils.js b/src/utils.js
index e08ae45..123ec2a 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -38,7 +38,11 @@ export function condenseBlocks (editorState, blocks, options) {
blocks.forEach((block) => {
// Atomic blocks should be ignored (stripped)
if (block.getType() !== 'atomic') {
- text = text.push(replaceNewlines(block.getText()))
+ if (options.stripNewlines) {
+ text = text.push(replaceNewlines(block.getText()))
+ } else {
+ text = text.push(block.getText())
+ }
characterList = characterList.concat(block.getCharacterList())
}
})
diff --git a/test/fixtures/content.js b/test/fixtures/content.js
index 1175d9c..7e43b91 100644
--- a/test/fixtures/content.js
+++ b/test/fixtures/content.js
@@ -1,117 +1,117 @@
-export default {
- "entityMap": {
- "0": {
- "type": "LINK",
- "mutability": "MUTABLE",
- "data": {
- "url": "http://icelab.com.au"
- }
+export default {
+ 'entityMap': {
+ '0': {
+ 'type': 'LINK',
+ 'mutability': 'MUTABLE',
+ 'data': {
+ 'url': 'http://icelab.com.au',
+ },
},
- "1": {
- "type": "image",
- "mutability": "IMMUTABLE",
- "data": {
- "src": "http://placekitten.com/300/100"
- }
+ '1': {
+ 'type': 'image',
+ 'mutability': 'IMMUTABLE',
+ 'data': {
+ 'src': 'http://placekitten.com/300/100',
+ },
},
- "2": {
- "type": "LINK",
- "mutability": "MUTABLE",
- "data": {
- "url": "http://makenosound.com"
- }
+ '2': {
+ 'type': 'LINK',
+ 'mutability': 'MUTABLE',
+ 'data': {
+ 'url': 'http://makenosound.com',
+ },
+ },
+ '3': {
+ 'type': 'image',
+ 'mutability': 'IMMUTABLE',
+ 'data': {
+ 'src': 'http://placekitten.com/200/100',
+ },
},
- "3": {
- "type": "image",
- "mutability": "IMMUTABLE",
- "data": {
- "src": "http://placekitten.com/200/100"
- }
- }
},
- "blocks": [
+ 'blocks': [
{
- "key": "a34sd",
- "text": "Hello World!",
- "type": "unstyled",
- "depth": 0,
- "inlineStyleRanges": [
+ 'key': 'a34sd',
+ 'text': 'Hello World!',
+ 'type': 'unstyled',
+ 'depth': 0,
+ 'inlineStyleRanges': [
{
- "offset": 0,
- "length": 12,
- "style": "BOLD"
+ 'offset': 0,
+ 'length': 12,
+ 'style': 'BOLD',
},
{
- "offset": 6,
- "length": 6,
- "style": "ITALIC"
- }
+ 'offset': 6,
+ 'length': 6,
+ 'style': 'ITALIC',
+ },
],
- "entityRanges": [
+ 'entityRanges': [
{
- "offset": 0,
- "length": 5,
- "key": 0
- }
- ]
+ 'offset': 0,
+ 'length': 5,
+ 'key': 0,
+ },
+ ],
},
{
- "key": "2em79",
- "text": "I am new content.",
- "type": "unstyled",
- "depth": 0,
- "inlineStyleRanges": [],
- "entityRanges": []
+ 'key': '2em79',
+ 'text': 'I am new content.',
+ 'type': 'unstyled',
+ 'depth': 0,
+ 'inlineStyleRanges': [],
+ 'entityRanges': [],
},
{
- "key": "55vrh",
- "text": "🍺",
- "type": "atomic",
- "depth": 0,
- "inlineStyleRanges": [],
- "entityRanges": [
+ 'key': '55vrh',
+ 'text': '🍺',
+ 'type': 'atomic',
+ 'depth': 0,
+ 'inlineStyleRanges': [],
+ 'entityRanges': [
{
- "offset": 0,
- "length": 1,
- "key": 1
- }
- ]
+ 'offset': 0,
+ 'length': 1,
+ 'key': 1,
+ },
+ ],
},
{
- "key": "dodnk",
- "text": "I am more content.",
- "type": "unordered-list-item",
- "depth": 0,
- "inlineStyleRanges": [],
- "entityRanges": [
+ 'key': 'dodnk',
+ 'text': 'I am more content.',
+ 'type': 'unordered-list-item',
+ 'depth': 0,
+ 'inlineStyleRanges': [],
+ 'entityRanges': [
{
- "offset": 10,
- "length": 7,
- "key": 2
- }
- ]
+ 'offset': 10,
+ 'length': 7,
+ 'key': 2,
+ },
+ ],
},
{
- "key": "6103o",
- "text": "🍺",
- "type": "atomic",
- "depth": 0,
- "inlineStyleRanges": [],
- "entityRanges": [
+ 'key': '6103o',
+ 'text': '🍺',
+ 'type': 'atomic',
+ 'depth': 0,
+ 'inlineStyleRanges': [],
+ 'entityRanges': [
{
- "offset": 0,
- "length": 1,
- "key": 3
- }
- ]
+ 'offset': 0,
+ 'length': 1,
+ 'key': 3,
+ },
+ ],
},
{
- "key": "evsu5",
- "text": "",
- "type": "unstyled",
- "depth": 0,
- "inlineStyleRanges": [],
- "entityRanges": []
- }
- ]
-};
+ 'key': 'evsu5',
+ 'text': '',
+ 'type': 'unstyled',
+ 'depth': 0,
+ 'inlineStyleRanges': [],
+ 'entityRanges': [],
+ },
+ ],
+}