UNPKG

draftjs-md-converter-support-video

Version:

Converter for converting Draft.js state into Markdown and vice versa

466 lines (396 loc) 14.5 kB
'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 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); } } var utils = require('../utils/utils'); var defaultMarkdownDict = { BOLD: '__', ITALIC: '*' }; var blockStyleDict = { 'unordered-list-item': '- ', 'header-one': '# ', 'header-two': '## ', 'header-three': '### ', 'header-four': '#### ', 'header-five': '##### ', 'header-six': '###### ', blockquote: '> ' }; var wrappingBlockStyleDict = { 'code-block': '```' }; var getBlockStyle = function getBlockStyle(currentStyle, appliedBlockStyles) { if (currentStyle === 'ordered-list-item') { var counter = appliedBlockStyles.reduce(function (prev, style) { if (style === 'ordered-list-item') { return prev + 1; } return prev; }, 1); return counter + '. '; } return blockStyleDict[currentStyle] || ''; }; var applyWrappingBlockStyle = function applyWrappingBlockStyle(currentStyle, content) { if (currentStyle in wrappingBlockStyleDict) { var wrappingSymbol = wrappingBlockStyleDict[currentStyle]; return wrappingSymbol + '\n' + content + '\n' + wrappingSymbol; } return content; }; var applyAtomicStyle = function applyAtomicStyle(block, entityMap, content) { if (block.type !== 'atomic') return content; // strip the test that was added in the media block var strippedContent = content.substring(0, content.length - block.text.length); var key = block.entityRanges[0].key; var type = entityMap[key].type; var data = entityMap[key].data; if (type === 'EMBEDDED_LINK') { return strippedContent + '[[ embed url=' + utils.buildEmbeddedUrl(data.url || data.src) + ' ]]'; } return strippedContent + '![' + (data.fileName || '') + '](' + (data.url || data.src) + ')'; }; var getEntityStart = function getEntityStart(entity) { switch (entity.type) { case 'LINK': return '['; default: return ''; } }; var getEntityEnd = function getEntityEnd(entity) { switch (entity.type) { case 'LINK': return '](' + entity.data.url + ')'; default: return ''; } }; function fixWhitespacesInsideStyle(text, style) { var symbol = style.symbol; // Text before style-opening marker (including the marker) var pre = text.slice(0, style.range.start); // Text between opening and closing markers var body = text.slice(style.range.start, style.range.end); // Trimmed text between markers var bodyTrimmed = body.trim(); // Text after closing marker var post = text.slice(style.range.end); var bodyTrimmedStart = style.range.start + body.indexOf(bodyTrimmed); // Text between opening marker and trimmed content (leading spaces) var prefix = text.slice(style.range.start, bodyTrimmedStart); // Text between the end of trimmed content and closing marker (trailing spaces) var postfix = text.slice(bodyTrimmedStart + bodyTrimmed.length, style.range.end); // Temporary text that contains trimmed content wrapped into original pre- and post-texts var newText = '' + pre + bodyTrimmed + post; // Insert leading and trailing spaces between pre-/post- contents and their respective markers return newText.replace('' + symbol + bodyTrimmed + symbol, '' + prefix + symbol + bodyTrimmed + symbol + postfix); } function getInlineStyleRangesByLength(inlineStyleRanges) { return [].concat(_toConsumableArray(inlineStyleRanges)).sort(function (a, b) { return b.length - a.length; }); // const concatArray = [[].concat.apply([], inlineStyleRanges)]; // const response = concatArray.sort((a, b) => b.length - a.length); // return response; } // function mergeObj(obj1, obj2) { // var obj3 = {}; // for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } // for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } // return obj3; // } function draftjsToMd(raw, extraMarkdownDict) { var markdownDict = _extends({}, defaultMarkdownDict, extraMarkdownDict); var returnString = ''; var appliedBlockStyles = []; // totalOffset is a difference of index position between raw string and enhanced ones var totalOffset = 0; raw.blocks.forEach(function (block, blockIndex) { if (blockIndex !== 0) { returnString += '\n'; totalOffset = 0; } // add block style returnString += getBlockStyle(block.type, appliedBlockStyles); appliedBlockStyles.push(block.type); var appliedStyles = []; returnString += block.text.split('').reduce(function (text, currentChar, index) { var newText = text; var sortedInlineStyleRanges = getInlineStyleRangesByLength(block.inlineStyleRanges); // find all styled at this character var stylesStartAtChar = sortedInlineStyleRanges.filter(function (range) { return range.offset === index; }).filter(function (range) { return markdownDict[range.style]; }); // disregard styles not defined in the md dict // add the symbol to the md string and push the style in the applied styles stack stylesStartAtChar.forEach(function (currentStyle) { var symbolLength = markdownDict[currentStyle.style].length; newText += markdownDict[currentStyle.style]; totalOffset += symbolLength; appliedStyles.push({ symbol: markdownDict[currentStyle.style], range: { start: currentStyle.offset + totalOffset, end: currentStyle.offset + currentStyle.length + totalOffset }, end: currentStyle.offset + (currentStyle.length - 1) }); }); // check for entityRanges starting and add if existing var entitiesStartAtChar = block.entityRanges.filter(function (range) { return range.offset === index; }); entitiesStartAtChar.forEach(function (entity) { newText += getEntityStart(raw.entityMap[entity.key]); }); // add the current character to the md string newText += currentChar; // check for entityRanges ending and add if existing var entitiesEndAtChar = block.entityRanges.filter(function (range) { return range.offset + range.length - 1 === index; }); entitiesEndAtChar.forEach(function (entity) { newText += getEntityEnd(raw.entityMap[entity.key]); }); // apply the 'ending' tags for any styles that end in the current position in order (stack) while (appliedStyles.length !== 0 && appliedStyles[appliedStyles.length - 1].end === index) { var endingStyle = appliedStyles.pop(); newText += endingStyle.symbol; newText = fixWhitespacesInsideStyle(newText, endingStyle); totalOffset += endingStyle.symbol.length; } return newText; }, ''); returnString = applyWrappingBlockStyle(block.type, returnString); returnString = applyAtomicStyle(block, raw.entityMap, returnString); }); return returnString; } module.exports.draftjsToMd = draftjsToMd; 'use strict'; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var utils = require('../utils/utils'); var parse = require('@textlint/markdown-to-ast').parse; var defaultInlineStyles = { Strong: { type: 'BOLD', symbol: '__' }, Emphasis: { type: 'ITALIC', symbol: '*' } }; var defaultBlockStyles = { List: 'unordered-list-item', Header1: 'header-one', Header2: 'header-two', Header3: 'header-three', Header4: 'header-four', Header5: 'header-five', Header6: 'header-six', CodeBlock: 'code-block', BlockQuote: 'blockquote' }; var getBlockStyleForMd = function getBlockStyleForMd(node, blockStyles) { var style = node.type; var ordered = node.ordered; var depth = node.depth; if (style === 'List' && ordered) { return 'ordered-list-item'; } else if (style === 'Header') { return blockStyles['' + style + depth]; } else if (node.type === 'Paragraph' && node.children && node.children[0] && node.children[0].type === 'Image') { return 'atomic'; } else if (node.type === 'Paragraph' && node.raw && utils.testEmbed(node.raw)) { return 'atomic'; } return blockStyles[style]; }; var joinCodeBlocks = function joinCodeBlocks(splitMd) { var opening = splitMd.indexOf('```'); var closing = splitMd.indexOf('```', opening + 1); if (opening >= 0 && closing >= 0) { var codeBlock = splitMd.slice(opening, closing + 1); var codeBlockJoined = codeBlock.join('\n'); var updatedSplitMarkdown = [[].concat.apply([], splitMd).slice(0, opening), // ...splitMd.slice(0, opening), codeBlockJoined, // ...splitMd.slice(closing + 1) [].concat.apply([], splitMd).slice(0, closing + 1)]; return joinCodeBlocks(updatedSplitMarkdown); } return splitMd; }; var splitMdBlocks = function splitMdBlocks(md) { var splitMd = md.split('\n'); // Process the split markdown include the // one syntax where there's an block level opening // and closing symbol with content in the middle. var splitMdWithCodeBlocks = joinCodeBlocks(splitMd); return splitMdWithCodeBlocks; }; // function mergeObj2(obj1, obj2) { // var obj3 = {}; // for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; } // for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; } // return obj3; // } var parseMdLine = function parseMdLine(line, existingEntities) { var extraStyles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var inlineStyles = _extends({}, defaultInlineStyles, extraStyles.inlineStyles); var blockStyles = _extends({}, defaultBlockStyles, extraStyles.blockStyles); var astString = parse(line); var text = ''; var inlineStyleRanges = []; var entityRanges = []; var entityMap = existingEntities; var addInlineStyleRange = function addInlineStyleRange(offset, length, style) { inlineStyleRanges.push({ offset: offset, length: length, style: style }); }; var getRawLength = function getRawLength(children) { return children.reduce(function (prev, current) { return prev + (current.value ? current.value.length : 0); }, 0); }; var addLink = function addLink(child) { var entityKey = Object.keys(entityMap).length; entityMap[entityKey] = { type: 'LINK', mutability: 'MUTABLE', data: { url: child.url } }; entityRanges.push({ key: entityKey, length: getRawLength(child.children), offset: text.length }); }; var addImage = function addImage(child) { var entityKey = Object.keys(entityMap).length; entityMap[entityKey] = { type: 'IMAGE', mutability: 'IMMUTABLE', data: { url: child.url, src: child.url, fileName: child.alt || '' } }; entityRanges.push({ key: entityKey, length: 1, offset: text.length }); }; var addVideo = function addVideo(child) { var string = child.raw; var url = utils.buildEmbeddedUrl(string); var entityKey = Object.keys(entityMap).length; entityMap[entityKey] = { type: 'EMBEDDED_LINK', mutability: 'IMMUTABLE', data: { src: url } }; entityRanges.push({ key: entityKey, length: 1, offset: text.length }); }; var parseChildren = function parseChildren(child, style) { switch (child.type) { case 'Link': addLink(child); break; case 'Image': addImage(child); break; case 'Paragraph': if (utils.testEmbed(child.raw)) { addVideo(child); } break; default: } if (!utils.testEmbed(child.raw) && child.children && style) { var rawLength = getRawLength(child.children); addInlineStyleRange(text.length, rawLength, style.type); var newStyle = inlineStyles[child.type]; child.children.forEach(function (grandChild) { parseChildren(grandChild, newStyle); }); } else if (!utils.testEmbed(child.raw) && child.children) { var _newStyle = inlineStyles[child.type]; child.children.forEach(function (grandChild) { parseChildren(grandChild, _newStyle); }); } else { if (style) { addInlineStyleRange(text.length, child.value.length, style.type); } if (inlineStyles[child.type]) { addInlineStyleRange(text.length, child.value.length, inlineStyles[child.type].type); } text = '' + text + (child.type === 'Image' || utils.testEmbed(child.raw) ? ' ' : child.value); } }; astString.children.forEach(function (child) { var style = inlineStyles[child.type]; parseChildren(child, style); }); // add block style if it exists var blockStyle = 'unstyled'; if (astString.children[0]) { var style = getBlockStyleForMd(astString.children[0], blockStyles); if (style) { blockStyle = style; } } return { text: text, inlineStyleRanges: inlineStyleRanges, entityRanges: entityRanges, blockStyle: blockStyle, entityMap: entityMap }; }; function mdToDraftjs(mdString, extraStyles) { var paragraphs = splitMdBlocks(mdString); var blocks = []; var entityMap = {}; paragraphs.forEach(function (paragraph) { var result = parseMdLine(paragraph, entityMap, extraStyles); blocks.push({ text: result.text, type: result.blockStyle, depth: 0, inlineStyleRanges: result.inlineStyleRanges, entityRanges: result.entityRanges }); entityMap = result.entityMap; }); // add a default value // not sure why that's needed but Draftjs convertToRaw fails without it if (Object.keys(entityMap).length === 0) { entityMap = { data: '', mutability: '', type: '' }; } return { blocks: blocks, entityMap: entityMap }; } module.exports.mdToDraftjs = mdToDraftjs; module.exports.buildEmbeddedUrl = utils.buildEmbeddedUrl; module.exports.getId = utils.getId; module.exports.getEmbedProvider = utils.getEmbedProvider;