From a919c2bd8fb568429d61ad219c40ef35b417a767 Mon Sep 17 00:00:00 2001 From: John Grishin Date: Thu, 16 Jun 2016 14:08:40 +0300 Subject: [PATCH 1/6] Added option to enable/disable stripping of newline characters `\n` --- README.md | 20 ++++++++++++++++++-- lib/index.js | 7 +++++-- src/index.js | 5 ++++- 3 files changed, 27 insertions(+), 5 deletions(-) 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 index 7c66fb5..c367506 100644 --- a/lib/index.js +++ b/lib/index.js @@ -15,7 +15,8 @@ var _utils = require('./utils'); * @type {Object} */ var defaultOptions = { - stripEntities: true + stripEntities: true, + stripNewlines: true }; /** @@ -67,7 +68,9 @@ function singleLinePlugin() { 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); + if (options.stripNewlines === true) { + text = (0, _utils.replaceNewlines)(text); + } // Strip entities? if (options.stripEntities) { diff --git a/src/index.js b/src/index.js index 89d98be..83eb50d 100644 --- a/src/index.js +++ b/src/index.js @@ -20,6 +20,7 @@ import { */ const defaultOptions = { stripEntities: true, + stripNewlines: true, } /** @@ -69,7 +70,9 @@ function singleLinePlugin (options = {}) { if (NEWLINE_REGEX.test(text) || 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 === true) { + text = replaceNewlines(text) + } // Strip entities? if (options.stripEntities) { From b00667241ecc4a7719e557e733343022c3a8f278 Mon Sep 17 00:00:00 2001 From: John Grishin Date: Thu, 16 Jun 2016 16:00:20 +0300 Subject: [PATCH 2/6] Extend check stripNewlines option In utils condenseBlock and before proccessing text --- lib/index.js | 12 +++++++++--- lib/utils.js | 6 +++++- src/index.js | 8 +++++--- src/utils.js | 6 +++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/index.js b/lib/index.js index c367506..751eb43 100644 --- a/lib/index.js +++ b/lib/index.js @@ -8,8 +8,14 @@ var _immutable = require('immutable'); var _draftJs = require('draft-js'); +var _isSoftNewlineEvent = require('draft-js/lib/isSoftNewlineEvent'); + +var _isSoftNewlineEvent2 = _interopRequireDefault(_isSoftNewlineEvent); + var _utils = require('./utils'); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + /** * Default options * @type {Object} @@ -64,11 +70,12 @@ function singleLinePlugin() { var contentBlock = blocks[0]; var text = contentBlock.getText(); var characterList = contentBlock.getCharacterList(); + var isNewLine = options.stripNewlines && _utils.NEWLINE_REGEX.test(text); - if (_utils.NEWLINE_REGEX.test(text) || (0, _utils.characterListhasEntities)(characterList)) { + if (isNewLine || (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 - if (options.stripNewlines === true) { + if (options.stripNewlines) { text = (0, _utils.replaceNewlines)(text); } @@ -87,7 +94,6 @@ function singleLinePlugin() { }); // 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 diff --git a/lib/utils.js b/lib/utils.js index 02ae41e..ff8789d 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -47,7 +47,11 @@ function condenseBlocks(editorState, blocks, options) { blocks.forEach(function (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/src/index.js b/src/index.js index 83eb50d..1bc745b 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,8 @@ import { genKey, } from 'draft-js' +import isSoftNewlineEvent from 'draft-js/lib/isSoftNewlineEvent' + import { NEWLINE_REGEX, replaceNewlines, @@ -66,11 +68,12 @@ 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 - if (options.stripNewlines === true) { + if (options.stripNewlines) { text = replaceNewlines(text) } @@ -89,7 +92,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..8f7d756 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()) } }) From 60662865b3dacde77b36c81c6409da3b90ae67c3 Mon Sep 17 00:00:00 2001 From: John Grishin Date: Thu, 16 Jun 2016 16:01:28 +0300 Subject: [PATCH 3/6] Bump version: 0.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 325e412..b63a4bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "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", "scripts": { From e56f623902ecf568b6dbdc22da680ab25a93d66d Mon Sep 17 00:00:00 2001 From: John Grishin Date: Wed, 7 Dec 2016 17:51:16 +0300 Subject: [PATCH 4/6] Fix codestyle rules --- .eslintrc | 14 +-- src/index.js | 6 +- src/utils.js | 2 +- test/fixtures/content.js | 188 +++++++++++++++++++-------------------- 4 files changed, 104 insertions(+), 106 deletions(-) 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/src/index.js b/src/index.js index 1bc745b..d7c6469 100644 --- a/src/index.js +++ b/src/index.js @@ -6,8 +6,6 @@ import { genKey, } from 'draft-js' -import isSoftNewlineEvent from 'draft-js/lib/isSoftNewlineEvent' - import { NEWLINE_REGEX, replaceNewlines, @@ -68,9 +66,9 @@ function singleLinePlugin (options = {}) { let contentBlock = blocks[0] let text = contentBlock.getText() let characterList = contentBlock.getCharacterList() - const isNewLine = (options.stripNewlines && NEWLINE_REGEX.test(text)); + const isNewLine = (options.stripNewlines && NEWLINE_REGEX.test(text)) - if ( isNewLine || 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 if (options.stripNewlines) { diff --git a/src/utils.js b/src/utils.js index 8f7d756..123ec2a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -41,7 +41,7 @@ export function condenseBlocks (editorState, blocks, options) { if (options.stripNewlines) { text = text.push(replaceNewlines(block.getText())) } else { - text = text.push(block.getText()); + 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': [], + }, + ], +} From 03472f49e78d042625f81e812c0c19e7819fb8d5 Mon Sep 17 00:00:00 2001 From: John Grishin Date: Wed, 7 Dec 2016 17:58:08 +0300 Subject: [PATCH 5/6] Remove lib folder and exclude compiled code from repository --- .gitignore | 1 + lib/index.js | 121 --------------------------------------------------- lib/utils.js | 103 ------------------------------------------- package.json | 5 +-- 4 files changed, 3 insertions(+), 227 deletions(-) delete mode 100644 lib/index.js delete mode 100644 lib/utils.js 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/lib/index.js b/lib/index.js deleted file mode 100644 index 751eb43..0000000 --- a/lib/index.js +++ /dev/null @@ -1,121 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _immutable = require('immutable'); - -var _draftJs = require('draft-js'); - -var _isSoftNewlineEvent = require('draft-js/lib/isSoftNewlineEvent'); - -var _isSoftNewlineEvent2 = _interopRequireDefault(_isSoftNewlineEvent); - -var _utils = require('./utils'); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -/** - * Default options - * @type {Object} - */ -var defaultOptions = { - stripEntities: true, - stripNewlines: 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(); - var isNewLine = options.stripNewlines && _utils.NEWLINE_REGEX.test(text); - - if (isNewLine || (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 - if (options.stripNewlines) { - 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 - 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 ff8789d..0000000 --- a/lib/utils.js +++ /dev/null @@ -1,103 +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') { - if (options.stripNewlines) { - text = text.push(replaceNewlines(block.getText())); - } else { - text = text.push(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 b63a4bd..9eb3be6 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,12 @@ "description": "Restrict a draft-js editor to a single line of input.", "main": "lib/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": { From 7cfc4528b1fc753234e982d567bb55bab2142fe1 Mon Sep 17 00:00:00 2001 From: John Grishin Date: Wed, 7 Dec 2016 18:11:23 +0300 Subject: [PATCH 6/6] Fix dist script location --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9eb3be6..210fa14 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "draft-js-single-line-plugin", "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 dist", "compile": "npm run build",