UNPKG

@20minutes/draft-convert

Version:

Extensibly serialize & deserialize Draft.js ContentState

91 lines (90 loc) 5.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return _default; } }); const _tinyinvariant = /*#__PURE__*/ _interop_require_default(require("tiny-invariant")); const _defaultInlineHTML = /*#__PURE__*/ _interop_require_default(require("./default/defaultInlineHTML.js")); const _accumulateFunction = /*#__PURE__*/ _interop_require_default(require("./util/accumulateFunction.js")); const _getElementHTML = /*#__PURE__*/ _interop_require_default(require("./util/getElementHTML.js")); const _rangeSort = /*#__PURE__*/ _interop_require_default(require("./util/rangeSort.js")); const _styleObjectFunction = /*#__PURE__*/ _interop_require_default(require("./util/styleObjectFunction.js")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const subtractStyles = (original, toRemove)=>original.filter((el)=>!toRemove.some((elToRemove)=>elToRemove.style === el.style)); const popEndingStyles = (styleStack, endingStyles)=>endingStyles.reduceRight((stack, style)=>{ const styleToRemove = stack[stack.length - 1]; (0, _tinyinvariant.default)(styleToRemove.style === style.style, `Style ${styleToRemove.style} to be removed doesn't match expected ${style.style}`); return stack.slice(0, -1); }, styleStack); const characterStyles = (offset, ranges)=>ranges.filter((range)=>offset >= range.offset && offset < range.offset + range.length); const rangeIsSubset = (firstRange, secondRange)=>{ // returns true if the second range is a subset of the first const secondStartWithinFirst = firstRange.offset <= secondRange.offset; const secondEndWithinFirst = firstRange.offset + firstRange.length >= secondRange.offset + secondRange.length; return secondStartWithinFirst && secondEndWithinFirst; }; const latestStyleLast = (s1, s2)=>{ // make sure longer-lasting styles are added first const s2endIndex = s2.offset + s2.length; const s1endIndex = s1.offset + s1.length; return s2endIndex - s1endIndex; }; const getStylesToReset = (remainingStyles, newStyles)=>{ let i = 0; while(i < remainingStyles.length){ if (newStyles.every(rangeIsSubset.bind(null, remainingStyles[i]))) { i += 1; } else { return remainingStyles.slice(i); } } return []; }; const appendStartMarkup = (inlineHTML, string, styleRange)=>string + (0, _getElementHTML.default)(inlineHTML(styleRange.style)).start; const prependEndMarkup = (inlineHTML, string, styleRange)=>(0, _getElementHTML.default)(inlineHTML(styleRange.style)).end + string; const defaultCustomInlineHTML = (next)=>(style)=>next(style); defaultCustomInlineHTML.__isMiddleware = true; const _default = (rawBlock, customInlineHTML = defaultCustomInlineHTML)=>{ (0, _tinyinvariant.default)(rawBlock !== null && rawBlock !== undefined, 'Expected raw block to be non-null'); let inlineHTML; if (customInlineHTML.__isMiddleware === true) { inlineHTML = customInlineHTML(_defaultInlineHTML.default); } else { inlineHTML = (0, _accumulateFunction.default)((0, _styleObjectFunction.default)(customInlineHTML), (0, _styleObjectFunction.default)(_defaultInlineHTML.default)); } let result = ''; let styleStack = []; const sortedRanges = rawBlock.inlineStyleRanges.sort(_rangeSort.default); const originalTextArray = [ ...rawBlock.text ]; for(let i = 0; i < originalTextArray.length; i += 1){ const styles = characterStyles(i, sortedRanges); const endingStyles = subtractStyles(styleStack, styles); const newStyles = subtractStyles(styles, styleStack); const 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. const resetStyles = getStylesToReset(remainingStyles, newStyles); const openingStyles = resetStyles.concat(newStyles).sort(latestStyleLast); const openingStyleTags = openingStyles.reduce(appendStartMarkup.bind(null, inlineHTML), ''); const endingStyleTags = endingStyles.concat(resetStyles).reduce(prependEndMarkup.bind(null, inlineHTML), ''); result += endingStyleTags + openingStyleTags + originalTextArray[i]; styleStack = popEndingStyles(styleStack, resetStyles.concat(endingStyles)); styleStack = styleStack.concat(openingStyles); (0, _tinyinvariant.default)(styleStack.length === styles.length, `Character ${i}: ${styleStack.length - styles.length} styles left on stack that should no longer be there`); } result = styleStack.reduceRight((res, openStyle)=>res + (0, _getElementHTML.default)(inlineHTML(openStyle.style)).end, result); return result; };