Comparing version
@@ -9,4 +9,12 @@ 'use strict'; | ||
var _arrayEqual = require('./helpers/arrayEqual'); | ||
var _arrayEqual2 = _interopRequireDefault(_arrayEqual); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); } | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -22,3 +30,6 @@ | ||
this.entity = typeof props.entity !== 'undefined' ? props.entity : null; | ||
this.decorator = typeof props.decorator !== 'undefined' ? props.decorator : null; | ||
this.decoratedText = typeof props.decoratedText !== 'undefined' ? props.decoratedText : null; | ||
this.style = props.style || null; | ||
this.styles = props.styles || null; | ||
} | ||
@@ -37,9 +48,22 @@ | ||
}, { | ||
key: 'handleFlatPush', | ||
value: function handleFlatPush(string, stack) { | ||
var current = this.getCurrentContent(); | ||
// if the stacks are equal just add the string to the current node | ||
if (current instanceof ContentNode && (0, _arrayEqual2.default)(stack, current.styles)) { | ||
current.addToCurrentContent(string); | ||
return; | ||
} | ||
// create a node with whole styles stack | ||
var newNode = new ContentNode({ styles: [].concat(_toConsumableArray(stack)), content: [string] }); | ||
this.content.push(newNode); | ||
} | ||
}, { | ||
key: 'pushContent', | ||
value: function pushContent(string) { | ||
var stack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
var flat = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
// we can just concat strings in case when both the pushed item | ||
// and the last element of the content array is a string | ||
// log | ||
if (!stack || stack.length < 1) { | ||
@@ -53,15 +77,18 @@ if (typeof string === 'string' && typeof this.getCurrentContent() === 'string') { | ||
} | ||
// hnadle flat structure | ||
if (flat) { | ||
this.handleFlatPush(string, stack); | ||
return this; | ||
} | ||
var _stack = _toArray(stack); | ||
var _stack = _toArray(stack), | ||
head = _stack[0], | ||
rest = _stack.slice(1); | ||
var head = _stack[0]; | ||
var rest = _stack.slice(1); | ||
var current = this.getCurrentContent(); | ||
if (current instanceof ContentNode && current.style === head) { | ||
current.pushContent(string, rest); | ||
current.pushContent(string, rest, flat); | ||
} else { | ||
var newNode = new ContentNode({ style: head }); | ||
newNode.pushContent(string, rest); | ||
newNode.pushContent(string, rest, flat); | ||
this.content.push(newNode); | ||
@@ -68,0 +95,0 @@ } |
@@ -6,3 +6,3 @@ 'use strict'; | ||
}); | ||
exports.renderNode = exports.RawParser = undefined; | ||
exports.renderNode = exports.RawParser = exports.createStylesRenderer = undefined; | ||
@@ -13,2 +13,6 @@ var _RawParser = require('./RawParser'); | ||
var _createStyleRenderer = require('./createStyleRenderer'); | ||
var _createStyleRenderer2 = _interopRequireDefault(_createStyleRenderer); | ||
var _render = require('./render'); | ||
@@ -18,4 +22,5 @@ | ||
exports.createStylesRenderer = _createStyleRenderer2.default; | ||
exports.RawParser = _RawParser2.default; | ||
exports.renderNode = _render.renderNode; | ||
exports.default = _render.render; |
@@ -17,15 +17,30 @@ 'use strict'; | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
/** | ||
* Slices the decoded ucs2 array and encodes the result back to a string representation | ||
*/ | ||
var getString = function getString(array, from, to) { | ||
return array.slice(from, to).join(''); | ||
}; | ||
/** | ||
* creates nodes with entity keys and the endOffset | ||
*/ | ||
function createEntityNodes(entityRanges, text) { | ||
function createNodes(entityRanges) { | ||
var decoratorRanges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
var textArray = arguments[2]; | ||
var lastIndex = 0; | ||
var mergedRanges = [].concat(_toConsumableArray(entityRanges), _toConsumableArray(decoratorRanges)).sort(function (a, b) { | ||
return a.offset - b.offset; | ||
}); | ||
var nodes = []; | ||
// if thers no entities will return just a single item | ||
if (entityRanges.length < 1) { | ||
nodes.push(new _ContentNode2.default({ start: 0, end: text.length })); | ||
if (mergedRanges.length < 1) { | ||
nodes.push(new _ContentNode2.default({ start: 0, end: textArray.length })); | ||
return nodes; | ||
} | ||
entityRanges.forEach(function (range) { | ||
mergedRanges.forEach(function (range) { | ||
// create an empty node for content between previous and this entity | ||
@@ -38,2 +53,4 @@ if (range.offset > lastIndex) { | ||
entity: range.key, | ||
decorator: range.component, | ||
decoratedText: range.component ? getString(textArray, range.offset, range.offset + range.length) : undefined, | ||
start: range.offset, | ||
@@ -46,6 +63,6 @@ end: range.offset + range.length | ||
// finaly add a node for the remaining text if any | ||
if (lastIndex < text.length) { | ||
if (lastIndex < textArray.length) { | ||
nodes.push(new _ContentNode2.default({ | ||
start: lastIndex, | ||
end: text.length | ||
end: textArray.length | ||
})); | ||
@@ -69,2 +86,3 @@ } | ||
var entityRanges = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; | ||
var decoratorRanges = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; | ||
@@ -75,2 +93,3 @@ var relevantIndexes = []; | ||
relevantIndexes = addIndexes(relevantIndexes, entityRanges); | ||
relevantIndexes = addIndexes(relevantIndexes, decoratorRanges); | ||
// add text start and end to relevant indexes | ||
@@ -88,12 +107,10 @@ relevantIndexes.push(0); | ||
/** | ||
* Slices the decoded ucs2 array and encodes the result back to a string representation | ||
*/ | ||
var getString = function getString(array, from, to) { | ||
return array.slice(from, to).join(''); | ||
}; | ||
var RawParser = function () { | ||
function RawParser(_ref) { | ||
var _ref$flat = _ref.flat, | ||
flat = _ref$flat === undefined ? false : _ref$flat; | ||
var RawParser = function () { | ||
function RawParser() { | ||
_classCallCheck(this, RawParser); | ||
this.flat = flat; | ||
} | ||
@@ -127,3 +144,2 @@ | ||
var characterStyles = _this.relevantStyles(index); | ||
// calculate distance or set it to 1 if thers no next index | ||
@@ -133,7 +149,7 @@ var distance = indexes[key + 1] ? indexes[key + 1] - index : 1; | ||
var text = getString(_this.textArray, index, index + distance); | ||
node.pushContent(text, characterStyles); | ||
node.pushContent(text, characterStyles, _this.flat); | ||
// if thers no next index and thers more text left to push | ||
if (!indexes[key + 1] && index < end) { | ||
node.pushContent(getString(_this.textArray, index + 1, end), _this.relevantStyles(end - 1)); | ||
node.pushContent(getString(_this.textArray, index + 1, end), _this.relevantStyles(end - 1), _this.flat); | ||
} | ||
@@ -152,8 +168,10 @@ }); | ||
key: 'parse', | ||
value: function parse(_ref) { | ||
value: function parse(_ref2) { | ||
var _this2 = this; | ||
var text = _ref.text; | ||
var ranges = _ref.inlineStyleRanges; | ||
var entityRanges = _ref.entityRanges; | ||
var text = _ref2.text, | ||
ranges = _ref2.inlineStyleRanges, | ||
entityRanges = _ref2.entityRanges, | ||
_ref2$decoratorRanges = _ref2.decoratorRanges, | ||
decoratorRanges = _ref2$decoratorRanges === undefined ? [] : _ref2$decoratorRanges; | ||
@@ -166,9 +184,6 @@ // Some unicode charactes actualy have length of more than 1 | ||
// get all the relevant indexes for whole block | ||
this.relevantIndexes = getRelevantIndexes(text, ranges, entityRanges); | ||
this.relevantIndexes = getRelevantIndexes(text, ranges, entityRanges, decoratorRanges); | ||
// create entity or empty nodes to place the inline styles in | ||
var entityNodes = createEntityNodes(entityRanges, text); | ||
var parsedNodes = entityNodes.map(function (node) { | ||
// reset the stacks | ||
_this2.styleStack = []; | ||
_this2.stylesToRemove = []; | ||
var nodes = createNodes(entityRanges, decoratorRanges, this.textArray); | ||
var parsedNodes = nodes.map(function (node) { | ||
return _this2.nodeIterator(node, node.start, node.end); | ||
@@ -175,0 +190,0 @@ }); |
@@ -12,60 +12,39 @@ 'use strict'; | ||
var _warn = require('./warn'); | ||
var _warn = require('./helpers/warn'); | ||
var _warn2 = _interopRequireDefault(_warn); | ||
var _checkClenup = require('./checkClenup'); | ||
var _checkCleanup = require('./helpers/checkCleanup'); | ||
var _checkClenup2 = _interopRequireDefault(_checkClenup); | ||
var _checkCleanup2 = _interopRequireDefault(_checkCleanup); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _getKeyGenerator = require('./helpers/getKeyGenerator'); | ||
var defaultOptions = { | ||
joinOutput: false, | ||
cleanup: { | ||
after: ['atomic'], | ||
types: ['unstyled'], | ||
trim: false, | ||
split: true | ||
} | ||
}; | ||
var _getKeyGenerator2 = _interopRequireDefault(_getKeyGenerator); | ||
/** | ||
* Concats or insets a string at given array index | ||
*/ | ||
var pushString = function pushString(string, array, index) { | ||
var tempArray = array; | ||
if (!array[index]) { | ||
tempArray[index] = string; | ||
} else { | ||
tempArray[index] += string; | ||
} | ||
return tempArray; | ||
}; | ||
var _checkJoin = require('./helpers/checkJoin'); | ||
/** | ||
* Joins the input if the joinOutput option is enabled | ||
*/ | ||
var checkJoin = function checkJoin(input, options) { | ||
if (Array.isArray(input) && options.joinOutput) { | ||
return input.join(''); | ||
} | ||
return input; | ||
}; | ||
var _checkJoin2 = _interopRequireDefault(_checkJoin); | ||
// return a new generator wich produces sequential keys for nodes | ||
var getKeyGenerator = function getKeyGenerator() { | ||
var key = 0; | ||
var keyGenerator = function keyGenerator() { | ||
var current = key; | ||
key += 1; | ||
return current; // eslint-disable-line no-plusplus | ||
}; | ||
return keyGenerator; | ||
}; | ||
var _pushString = require('./helpers/pushString'); | ||
var _pushString2 = _interopRequireDefault(_pushString); | ||
var _defaultOptions = require('./defaultOptions'); | ||
var _defaultOptions2 = _interopRequireDefault(_defaultOptions); | ||
var _withDecorators = require('./withDecorators'); | ||
var _withDecorators2 = _interopRequireDefault(_withDecorators); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
* Recursively renders a node with nested nodes with given callbacks | ||
*/ | ||
var renderNode = exports.renderNode = function renderNode(node, styleRenderers, entityRenderers, entityMap, options, keyGenerator) { | ||
var renderNode = exports.renderNode = function renderNode(node, inlineRenderers, entityRenderers, styleRenderers, entityMap, options, keyGenerator) { | ||
if (node.styles && styleRenderers) { | ||
return styleRenderers((0, _checkJoin2.default)(node.content, options), node.styles, { key: keyGenerator() }); | ||
} | ||
var children = []; | ||
@@ -75,11 +54,11 @@ var index = 0; | ||
if (typeof part === 'string') { | ||
children = pushString(part, children, index); | ||
children = (0, _pushString2.default)(part, children, index); | ||
} else { | ||
index += 1; | ||
children[index] = renderNode(part, styleRenderers, entityRenderers, entityMap, options, keyGenerator); | ||
children[index] = renderNode(part, inlineRenderers, entityRenderers, styleRenderers, entityMap, options, keyGenerator); | ||
index += 1; | ||
} | ||
}); | ||
if (node.style && styleRenderers[node.style]) { | ||
return styleRenderers[node.style](checkJoin(children, options), { key: keyGenerator() }); | ||
if (node.style && inlineRenderers[node.style]) { | ||
return inlineRenderers[node.style]((0, _checkJoin2.default)(children, options), { key: keyGenerator() }); | ||
} | ||
@@ -89,5 +68,11 @@ if (node.entity !== null) { | ||
if (entity && entityRenderers[entity.type]) { | ||
return entityRenderers[entity.type](checkJoin(children, options), entity.data, { key: node.entity }); | ||
return entityRenderers[entity.type]((0, _checkJoin2.default)(children, options), entity.data, { key: node.entity }); | ||
} | ||
} | ||
if (node.decorator !== null) { | ||
return node.decorator({ | ||
children: (0, _checkJoin2.default)(children, options), | ||
decoratedText: node.decoratedText | ||
}); | ||
} | ||
return children; | ||
@@ -138,6 +123,6 @@ }; | ||
var renderGroup = function renderGroup(group, blockRenderers, rendered, params) { | ||
var type = params.prevType; | ||
var depth = params.prevDepth; | ||
var keys = params.prevKeys; | ||
var data = params.prevData; | ||
var type = params.prevType, | ||
depth = params.prevDepth, | ||
keys = params.prevKeys, | ||
data = params.prevData; | ||
// in case current group is empty it should not be rendered | ||
@@ -166,7 +151,8 @@ | ||
var entityRenderers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
var entityMap = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; | ||
var userOptions = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; | ||
var stylesRenderer = arguments[4]; | ||
var entityMap = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; | ||
var userOptions = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {}; | ||
// initialize | ||
var options = Object.assign({}, defaultOptions, userOptions); | ||
var options = Object.assign({}, _defaultOptions2.default, userOptions); | ||
var rendered = []; | ||
@@ -179,6 +165,5 @@ var group = []; | ||
var splitGroup = false; | ||
var Parser = new _RawParser2.default(); | ||
var Parser = new _RawParser2.default({ flat: !!stylesRenderer }); | ||
blocks.forEach(function (block) { | ||
if ((0, _checkClenup2.default)(block, prevType, options)) { | ||
if ((0, _checkCleanup2.default)(block, prevType, options)) { | ||
// Set the split flag if enabled | ||
@@ -191,3 +176,3 @@ if (options.cleanup.split === true) { | ||
var node = Parser.parse(block); | ||
var renderedNode = renderNode(node, inlineRenderers, entityRenderers, entityMap, options, getKeyGenerator()); | ||
var renderedNode = renderNode(node, inlineRenderers, entityRenderers, stylesRenderer, entityMap, options, (0, _getKeyGenerator2.default)()); | ||
// if type of the block has changed or the split flag is set | ||
@@ -206,3 +191,3 @@ // render and clear group | ||
if (block.children) { | ||
var children = renderBlocks(block.children, inlineRenderers, blockRenderers, entityRenderers, entityMap, options); | ||
var children = renderBlocks(block.children, inlineRenderers, blockRenderers, entityRenderers, stylesRenderer, entityMap, options); | ||
renderedNode.push(children); | ||
@@ -221,3 +206,3 @@ } | ||
renderGroup(group, blockRenderers, rendered, { prevType: prevType, prevDepth: prevDepth, prevKeys: prevKeys, prevData: prevData }); | ||
return checkJoin(rendered, options); | ||
return (0, _checkJoin2.default)(rendered, options); | ||
}; | ||
@@ -240,9 +225,13 @@ | ||
} | ||
var inlineRenderers = renderers.inline; | ||
var blockRenderers = renderers.blocks; | ||
var entityRenderers = renderers.entities; | ||
var inlineRenderers = renderers.inline, | ||
blockRenderers = renderers.blocks, | ||
entityRenderers = renderers.entities, | ||
stylesRenderer = renderers.styles, | ||
decorators = renderers.decorators; | ||
// If decorators are present, they are maped with the blocks array | ||
var blocks = byDepth(raw.blocks); | ||
return renderBlocks(blocks, inlineRenderers, blockRenderers, entityRenderers, raw.entityMap, options); | ||
var blocksWithDecorators = decorators ? (0, _withDecorators2.default)(raw.blocks, decorators, options) : raw.blocks; | ||
// Nest blocks by depth | ||
var blocks = byDepth(blocksWithDecorators); | ||
return renderBlocks(blocks, inlineRenderers, blockRenderers, entityRenderers, stylesRenderer, raw.entityMap, options); | ||
}; |
{ | ||
"name": "redraft", | ||
"version": "0.7.0", | ||
"version": "0.8.0-beta.1", | ||
"description": "Renders the result of Draft.js convertToRaw using provided callbacks, works well with React", | ||
@@ -29,3 +29,4 @@ "main": "./lib/index.js", | ||
"babel-plugin-array-includes": "^2.0.3", | ||
"babel-preset-latest": "^6.16.0", | ||
"babel-preset-env": "^1.2.1", | ||
"babel-preset-react": "^6.23.0", | ||
"babel-register": "^6.16.3", | ||
@@ -38,5 +39,9 @@ "chai": "^3.5.0", | ||
"eslint-plugin-react": "^6.4.1", | ||
"linkify-it": "^2.0.3", | ||
"mocha": "^3.0.2", | ||
"rimraf": "^2.5.2" | ||
"react": "^15.4.2", | ||
"react-dom": "^15.4.2", | ||
"rimraf": "^2.5.2", | ||
"tlds": "^1.183.0" | ||
} | ||
} |
@@ -83,2 +83,15 @@ | ||
}, | ||
/** | ||
* Entities receive children and the entity data, | ||
* based on https://facebook.github.io/draft-js/docs/advanced-topics-decorators.html | ||
*/ | ||
decorators: [ | ||
{ | ||
// by default linkStrategy receives a ContentBlock stub | ||
strategy: linkStrategy, | ||
// component is just a callback as with other renderers, | ||
// decoratedText just the plain string matched by the strategy | ||
component: ({ children, decoratedText }) => <a href={decoratedText}>{children}/>, | ||
} | ||
], | ||
} | ||
@@ -124,18 +137,34 @@ | ||
Returns an array of rendered blocks. | ||
- raw - result of the Draft.js convertToRaw | ||
- renderers - object with 3 groups of renders inline, blocks and entities refer to example for more info | ||
- options - optional settings | ||
- **raw** - result of the Draft.js convertToRaw | ||
- **renderers** - object with 3 groups of renders inline (or style), blocks and entities refer to example for more info | ||
- **options** - optional settings | ||
#### Using style renderer instead of inline | ||
If provided with a style renderer in the renders, redraft will use it instead of the inline one. This allows a flatter render more like draft.js does in the editor. Redraft also exposes a helper to create the style renderer. | ||
```js | ||
RawParser.parse(block) | ||
``` | ||
Parses the provided block and returns an ContentNode object | ||
import React from 'react'; | ||
import redraft, { createStylesRenderer } from 'redraft'; | ||
```js | ||
renderNode(Object:node, Object:inlineRendrers, Object:entityRenderers, Object:entityMap, Object:options) | ||
const styleMap = { | ||
BOLD: { | ||
fontWeight: 'bold', | ||
}, | ||
ITALIC: { | ||
fontStyle: 'italic', | ||
}, | ||
UNDERLINE: { | ||
textDecoration: 'underline', | ||
}, | ||
}; | ||
// This is a wrapper callback for the inline styles | ||
// the style object contains all the relevant styles from the styleMap | ||
// it needs a key as redraft returns arrays not Components | ||
const InlineWrapper = ({ children, style, key }) => <span key={key} style={style}>{children}</span> | ||
const renderers = { | ||
style: createStylesRenderer(InlineWrapper, styleMap), | ||
... | ||
}; | ||
``` | ||
Returns an rendered single block. | ||
- node - ContentNode from `RawParser.parse(block)` method | ||
- inlineRendrers, entityRenderers - callbacks | ||
- entityMap - the entityMap from raw state `raw.entityMap` | ||
@@ -150,2 +179,3 @@ ### Options | ||
- `joinOutput` - used when rendering to string, joins the output and the children of all the inline and entity renderers, it expects that all renderers return strings, you still have to join the at block level (default: `false`) | ||
- `createContentBlock` - by default when using decorators redraft creates a ContentBlock stub, its possible to pass a callback that returns a draft-js ContentBlock | ||
@@ -152,0 +182,0 @@ ## Changelog |
Sorry, the diff of this file is not supported yet
245308
75.26%29
45%675
38.32%185
19.35%19
35.71%