UNPKG

@jonny/draft-convert

Version:

Extensibly serialize & deserialize Draft.js ContentState

147 lines (106 loc) 5.35 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _styleObjectFunction = require('./util/styleObjectFunction'); var _styleObjectFunction2 = _interopRequireDefault(_styleObjectFunction); var _accumulateFunction = require('./util/accumulateFunction'); var _accumulateFunction2 = _interopRequireDefault(_accumulateFunction); var _getElementHTML = require('./util/getElementHTML'); var _getElementHTML2 = _interopRequireDefault(_getElementHTML); var _rangeSort = require('./util/rangeSort'); var _rangeSort2 = _interopRequireDefault(_rangeSort); var _defaultInlineHTML = require('./default/defaultInlineHTML'); var _defaultInlineHTML2 = _interopRequireDefault(_defaultInlineHTML); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var subtractStyles = function subtractStyles(original, toRemove) { return original.filter(function (el) { return !toRemove.some(function (elToRemove) { return elToRemove.style === el.style; }); }); }; var popEndingStyles = function popEndingStyles(styleStack, endingStyles) { return endingStyles.reduceRight(function (stack, style) { var styleToRemove = stack[stack.length - 1]; (0, _invariant2.default)(styleToRemove.style === style.style, 'Style ' + styleToRemove.style + ' to be removed doesn\'t match expected ' + style.style); return stack.slice(0, -1); }, styleStack); }; var characterStyles = function characterStyles(offset, ranges) { return ranges.filter(function (range) { return offset >= range.offset && offset < range.offset + range.length; }); }; var rangeIsSubset = function rangeIsSubset(firstRange, secondRange) { // returns true if the second range is a subset of the first var secondStartWithinFirst = firstRange.offset <= secondRange.offset; var secondEndWithinFirst = firstRange.offset + firstRange.length >= secondRange.offset + secondRange.length; return secondStartWithinFirst && secondEndWithinFirst; }; var latestStyleLast = function latestStyleLast(s1, s2) { // make sure longer-lasting styles are added first var s2endIndex = s2.offset + s2.length; var s1endIndex = s1.offset + s1.length; return s2endIndex - s1endIndex; }; var getStylesToReset = function getStylesToReset(remainingStyles, newStyles) { var i = 0; while (i < remainingStyles.length) { if (newStyles.every(rangeIsSubset.bind(null, remainingStyles[i]))) { i++; } else { return remainingStyles.slice(i); } } return []; }; var appendStartMarkup = function appendStartMarkup(inlineHTML, string, styleRange) { return string + (0, _getElementHTML2.default)(inlineHTML(styleRange.style)).start; }; var prependEndMarkup = function prependEndMarkup(inlineHTML, string, styleRange) { return (0, _getElementHTML2.default)(inlineHTML(styleRange.style)).end + string; }; var defaultCustomInlineHTML = function defaultCustomInlineHTML(next) { return function (style) { return next(style); }; }; defaultCustomInlineHTML.__isMiddleware = true; exports.default = function (rawBlock) { var customInlineHTML = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultCustomInlineHTML; (0, _invariant2.default)(rawBlock !== null && rawBlock !== undefined, 'Expected raw block to be non-null'); var inlineHTML = void 0; if (customInlineHTML.__isMiddleware === true) { inlineHTML = customInlineHTML(_defaultInlineHTML2.default); } else { inlineHTML = (0, _accumulateFunction2.default)((0, _styleObjectFunction2.default)(customInlineHTML), (0, _styleObjectFunction2.default)(_defaultInlineHTML2.default)); } var result = ''; var styleStack = []; var sortedRanges = rawBlock.inlineStyleRanges.sort(_rangeSort2.default); for (var i = 0; i < rawBlock.text.length; i++) { var styles = characterStyles(i, sortedRanges); var endingStyles = subtractStyles(styleStack, styles); var newStyles = subtractStyles(styles, styleStack); var remainingStyles = subtractStyles(styleStack, endingStyles); // reset styles: look for any already existing styles that will need to // end before styles that are being added on this character. to solve this // close out those current tags and all nested children, // then open new ones nested within the new styles. var resetStyles = getStylesToReset(remainingStyles, newStyles); var openingStyles = resetStyles.concat(newStyles).sort(latestStyleLast); var openingStyleTags = openingStyles.reduce(appendStartMarkup.bind(null, inlineHTML), ''); var endingStyleTags = endingStyles.concat(resetStyles).reduce(prependEndMarkup.bind(null, inlineHTML), ''); result += endingStyleTags + openingStyleTags + rawBlock.text[i]; styleStack = popEndingStyles(styleStack, resetStyles.concat(endingStyles)); styleStack = styleStack.concat(openingStyles); (0, _invariant2.default)(styleStack.length === styles.length, 'Character ' + i + ': ' + (styleStack.length - styles.length) + ' styles left on stack that should no longer be there'); } result = styleStack.reduceRight(function (res, openStyle) { return res + (0, _getElementHTML2.default)(inlineHTML(openStyle.style)).end; }, result); return result; };