UNPKG

redraft

Version:

Renders the result of Draft.js convertToRaw using provided callbacks, works well with React

241 lines (211 loc) 8.31 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.render = exports.renderNode = undefined; var _RawParser = require('./RawParser'); var _RawParser2 = _interopRequireDefault(_RawParser); var _warn = require('./helpers/warn'); var _warn2 = _interopRequireDefault(_warn); var _checkCleanup = require('./helpers/checkCleanup'); var _checkCleanup2 = _interopRequireDefault(_checkCleanup); var _getKeyGenerator = require('./helpers/getKeyGenerator'); var _getKeyGenerator2 = _interopRequireDefault(_getKeyGenerator); var _checkJoin = require('./helpers/checkJoin'); var _checkJoin2 = _interopRequireDefault(_checkJoin); 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 }; } var KEY_DELIMITER = '.'; /** * Recursively renders a node with nested nodes with given callbacks */ 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 = []; var index = 0; node.content.forEach(function (part) { if (typeof part === 'string') { children = (0, _pushString2.default)(part, children, index); } else { index += 1; children[index] = renderNode(part, inlineRenderers, entityRenderers, styleRenderers, entityMap, options, keyGenerator); index += 1; } }); if (node.style && inlineRenderers[node.style]) { return inlineRenderers[node.style]((0, _checkJoin2.default)(children, options), { key: keyGenerator() }); } if (node.entity !== null) { var entity = entityMap[node.entity]; if (entity && entityRenderers[entity.type]) { return entityRenderers[entity.type]((0, _checkJoin2.default)(children, options), entity.data, { key: node.entity }); } } if (node.decorator !== null) { // FIXME: few props are missing see https://github.com/facebook/draft-js/blob/0c609d9d3671fdbbe2a290ed160a0537f846f08e/src/component/contents/DraftEditorBlock.react.js#L196-L205 var decoratorOffsetKey = [node.block.key, node.start, 0].join(KEY_DELIMITER); return node.decorator(Object.assign({ children: (0, _checkJoin2.default)(children, options), decoratedText: node.decoratedText, contentState: node.contentState, entityKey: node.entity, offsetKey: decoratorOffsetKey, key: decoratorOffsetKey }, node.decoratorProps)); } return children; }; /** * Nests blocks by depth as children */ var byDepth = function byDepth(blocks) { var group = []; var depthStack = []; var prevDepth = 0; var unwind = function unwind(targetDepth) { var i = prevDepth - targetDepth; // in case depthStack is too short for target depth if (depthStack.length < i) { i = depthStack.length; } for (i; i > 0; i -= 1) { var tmp = group; group = depthStack.pop(); group[group.length - 1].children = tmp; } }; blocks.forEach(function (block) { // if type of the block has changed render the block and clear group if (prevDepth < block.depth) { depthStack.push(group); group = []; } else if (prevDepth > block.depth) { unwind(block.depth); } prevDepth = block.depth; group.push(Object.assign({}, block)); }); if (prevDepth !== 0) { unwind(0); } return group; }; /** * Conditionaly render a group if its not empty, * pass all the params to the renderers */ var renderGroup = function renderGroup(group, blockRenderers, rendered, params, options) { var type = params.prevType, depth = params.prevDepth, keys = params.prevKeys, data = params.prevData; // in case current group is empty it should not be rendered if (group.length === 0) { return; } var renderCb = blockRenderers[type] || blockRenderers[options.blockFallback]; if (renderCb) { var props = { depth: depth, keys: keys }; if (data && data.some(function (item) { return !!item; })) { props.data = data; } rendered.push(renderCb(group, props)); return; } rendered.push(group); }; /** * Renders blocks grouped by type using provided blockStyleRenderers */ var renderBlocks = function renderBlocks(blocks) { var inlineRenderers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var blockRenderers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var entityRenderers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; 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({}, _defaultOptions2.default, userOptions); var rendered = []; var group = []; var prevType = null; var prevDepth = 0; var prevKeys = []; var prevData = []; var splitGroup = false; var Parser = new _RawParser2.default({ flat: !!stylesRenderer }); blocks.forEach(function (block) { if ((0, _checkCleanup2.default)(block, prevType, options)) { // Set the split flag if enabled if (options.cleanup.split === true) { splitGroup = true; } return; } var node = Parser.parse(block); 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 // render and clear group if (prevType && prevType !== block.type || splitGroup) { renderGroup(group, blockRenderers, rendered, { prevType: prevType, prevDepth: prevDepth, prevKeys: prevKeys, prevData: prevData }, options); // reset group vars // IDEA: might be worth to group those into an instance and just newup a new one prevData = []; prevKeys = []; group = []; splitGroup = false; } // handle children if (block.children) { var children = renderBlocks(block.children, inlineRenderers, blockRenderers, entityRenderers, stylesRenderer, entityMap, options); renderedNode.push(children); } // push current node to group group.push(renderedNode); // lastly save current type for refference prevType = block.type; prevDepth = block.depth; prevKeys.push(block.key); prevData.push(block.data); }); // render last group renderGroup(group, blockRenderers, rendered, { prevType: prevType, prevDepth: prevDepth, prevKeys: prevKeys, prevData: prevData }, options); return (0, _checkJoin2.default)(rendered, options); }; /** * Converts and renders each block of Draft.js rawState */ var render = exports.render = function render(raw) { var renderers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; if (!raw || !Array.isArray(raw.blocks)) { (0, _warn2.default)('invalid raw object'); return null; } // If the lenght of the blocks array is 0 its should not log a warning but still return a null if (!raw.blocks.length) { return null; } 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 blocksWithDecorators = decorators ? (0, _withDecorators2.default)(raw, decorators, options) : raw.blocks; // Nest blocks by depth var blocks = byDepth(blocksWithDecorators); return renderBlocks(blocks, inlineRenderers, blockRenderers, entityRenderers, stylesRenderer, raw.entityMap, options); };