@20minutes/draft-convert
Version:
Extensibly serialize & deserialize Draft.js ContentState
91 lines (90 loc) • 5.07 kB
JavaScript
;
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;
};