diff --git a/TODO.md b/TODO.md index a9ae5ef4..7e58b916 100644 --- a/TODO.md +++ b/TODO.md @@ -5,12 +5,12 @@ - [x] 段落和换行,两个或两个以上的空格再敲回车,或插入一个\
- [x] 标题,支持 atx 形式的标题,在行首插入 1 到 6 个 #,会生成对应的 h1~6 h 标签。在敲回车后再转换成 HTML,但是在编辑标题的时候,显示会加粗。标题支持嵌套其他 markdown 样式。支持嵌套的样式包括加粗、斜体、行内代码、链接、图片。 - [x] 区块引用 Blockquotes,每行前面都加上 > ,支持嵌套区块引用,支持嵌套其他 markdown 语法,比如标题、列表、代码区块。区块引用会生成 blockquote 标签。 -- [x] 列表,有序列表和无需列表。无序列表使用 *、+、- 作为列表标记。有序列表使用数字加一个英文句点来标记。列表支持嵌套列表。列表支持嵌套区块引用,但仅限于行首,支持嵌套代码区块,但仅限于行首,支持其他 markdown 语法嵌套。 +- [x] 列表,有序列表和无序列表。无序列表使用 *、+、- 作为列表标记。有序列表使用数字加一个英文句点来标记。列表支持嵌套列表。列表支持嵌套区块引用,但仅限于行首,支持嵌套代码区块,但仅限于行首,支持其他 markdown 语法嵌套。 - [x] 代码区块,代码区块中的 markdown 语法不再被转换。 - [x] 分割线,你可以在一行中使用三个以上的 *、-、_ 来创建分割线。 - [x] 链接,markdown 支持两种形式的链接,行内式、参考式。 - [ ] 图片,markdown 支持两种形式的图片,行内式、参考式。 -- [x] Markdown 中使用\*、\_ 来表示强调,使用一个用 em 标签,使用两个用 strong 标签,如果\*、\_ 两边都(?)有空白的话,会被当做普通的符号。 +- [x] Markdown 中使用\*、\_ 来表示强调,使用一个用 em 标签,使用两个用 strong 标签,如果\*、\_ 内侧有空白的话,会被当做普通的符号。 - [x] 代码,如果标记一小段代码,可以用反引号标记:\`。如果文字中已经有反引号,那么使用两个反引号。 - [x] 简单链接、自动连接,使用\<\>包裹的链接会被转换为a 标签,还可以自动识别链接。 - [ ] 反斜线 \ 可以对如下字符转义: diff --git a/src/editor/config.js b/src/editor/config.js index 1670666d..4c4f41d2 100644 --- a/src/editor/config.js +++ b/src/editor/config.js @@ -63,7 +63,9 @@ export const CLASS_OR_ID = genUpper2LowerKeyHash([ 'AG_LANGUAGE', 'AG_LANGUAGE_INPUT', 'AG_TEMP', - 'AG_LINK_IN_BRACKET' + 'AG_LINK_IN_BRACKET', + 'AG_BACKLASH', + 'AG_BUG' // for remove bug ]) export const codeMirrorConfig = { diff --git a/src/editor/index.css b/src/editor/index.css index e4e3ae7f..e0b320a1 100644 --- a/src/editor/index.css +++ b/src/editor/index.css @@ -157,6 +157,10 @@ span[role="link"], a[role="link"] { color: #708; text-decoration: none; } +.ag-backlash { + text-decoration: none; + color: rgb(51, 51, 51); +} .ag-warn { color: #000; text-decoration: none; diff --git a/src/editor/syntax/index.js b/src/editor/syntax/index.js index b2fc4012..29645f67 100644 --- a/src/editor/syntax/index.js +++ b/src/editor/syntax/index.js @@ -3,7 +3,7 @@ import { findOutMostParagraph, findNearestParagraph, isFirstChildElement, isOnlyChildElement } from '../utils/domManipulate' - +import { isEven } from '../utils' import { LOWERCASE_TAGS, CLASS_OR_ID, @@ -20,14 +20,14 @@ const fragments = [ '^`{3,}[^`]*', '^#{1,6}', // Header '(\\*{2}|_{2})(?:[^\\s]|[^\\s].*[^\\s])\\1', // strong - '(\\*{1}|_{1})(?:[^\\s]|[^\\s].*[^\\s])\\2', // em + '\\\\*(\\*{1}|_{1})(?:[^\\s]|[^\\s].*[^\\s])\\\\*\\2', // em '(`{1,3})([^`]+?|.{2,})\\3', // inline code '\\[[^\\[\\]]+\\]\\(.*?\\)', // link '\\[\\]\\([^\\(\\)]*?\\)', // no text link ':[^:]+?:', // emoji '~{2}[^~]+~{2}', // line through 'https?://[^\\s]+(?=\\s|$)', // auto link - `\\\\(?=[${markedSymbol.join()}]{1})` // eslint-disable-line no-useless-escape + `\\\\+(?=[${markedSymbol.join()}]{1})` // eslint-disable-line no-useless-escape ] const CHOP_REG = new RegExp(fragments.join('|'), 'g') // eslint-disable-line no-useless-escape @@ -38,8 +38,8 @@ const HEAD_REG = /^#{1,6}/ const STRONG_REG_G = /^(\*{2}|_{2})([^\s]|[^\s].*[^\s])(\1)/g const STRONG_REG = /^(\*{2}|_{2})(?:[^\s]|[^\s].*[^\s])\1/ -const EM_REG_G = /^(\*{1}|_{1})([^\s]|[^\s].*[^\s])(\1)/g -const EM_REG = /^(\*{1}|_{1})(?:[^\s]|[^\s].*[^\s])\1/ +const EM_REG_G = /^(\\*)(\*{1}|_{1})([^\s]|[^\s].*?[^\s])(\\*)(\2)/g +const EM_REG = /^(?:\\*)(\*{1}|_{1})(?:[^\s]|[^\s].*[^\s])(?:\\*)\1/ const INLINE_CODE_REG_G = /^(`{1,3})([^`]+?|.{2,})(\1)/g const INLINE_CODE_REG = /^(`{1,3})([^`]+?|.{2,})(\1)/ @@ -58,6 +58,9 @@ const HR_REG_G = /(^\*{3,}|^-{3,}|^_{3,})/g const HR_REG = /^\*{3,}|^-{3,}|^_{3,}/ const CODE_BLOCK_G = /(^`{3,})([^`]*)/g const CODE_BLOCK = /^`{3,}[^`]*/ +const BACKLASH_REG_G = new RegExp('^(\\\\+)', 'g') +const BACKLASH_REG = new RegExp('^\\\\+', 'i') + // const SIMPLE_LINK_G = /(<)([^<>]+?)(>)/g // const SIMPLE_LINK = /<[^<>]+?>/g const LINE_BREAK_BLOCK_REG = /^(?:`{3,}([^`]*))|[\*\-\_]{3,}/ // eslint-disable-line no-useless-escape @@ -70,6 +73,26 @@ const CHOP_HEADER_REG = /^([*+-]\s(?:\[\s\]\s)?|>\s*|\d+\.\s)/ const conflict = (arr1, arr2) => { return !(arr1[1] < arr2[0] || arr2[1] < arr1[0]) } +/** + * [backlash => html] + * examples: + * `\` => `\` + * `\\` => `\\` + */ +const backlash2html = (backlashes, className) => { + const chunks = backlashes.split('') + const len = chunks.length + let i + let result = '' + for (i = 0; i < len; i++) { + if (isEven(i)) { + result += `${chunks[i]}` + } else { + result += `${chunks[i]}` + } + } + return `${result}` // the extral a tag for fix the bug. +} const chunk2html = ({ chunk, index, lastIndex }, { start, end } = {}, outerClsssName) => { // if no positionState provided, no conflict. @@ -97,12 +120,23 @@ const chunk2html = ({ chunk, index, lastIndex }, { start, end } = {}, outerClsss // handle emphasize if (EM_REG.test(chunk)) { - return chunk.replace(EM_REG_G, (match, p1, p2, p3) => { - return ( - `${p1}` + - `${markedText2Html(p2, undefined, className, 'inline')}` + - `${p3}` - ) + console.log('em') + return chunk.replace(EM_REG_G, (match, p1, p2, p3, p4, p5) => { + console.log(`p1: ${p1}, p2: ${p2}, p3: ${p3}, p4: ${p4}, p5: ${p5}`) + if (isEven(p1.length) && isEven(p4.length)) { + return ( + backlash2html(p1, className) + + `${p2}` + + `${markedText2Html(p3, undefined, className, 'inline')}${backlash2html(p4, className)}` + + `${p5}` + ) + } else { + return ( + `${backlash2html(p1, className)}${p2}` + + `${markedText2Html(p3, undefined, className, 'inline')}` + + `${backlash2html(p4, className)}${p5}` + ) + } }) } // handle inline code: markdown text: `code` @@ -209,6 +243,12 @@ const chunk2html = ({ chunk, index, lastIndex }, { start, end } = {}, outerClsss }) } + if (BACKLASH_REG.test(chunk)) { + return chunk.replace(BACKLASH_REG_G, (match, p1) => { + return backlash2html(p1, className) + }) + } + // handle picture // TODO // handle auto link: markdown text: `` diff --git a/src/editor/utils/index.js b/src/editor/utils/index.js index 73c0df0e..6b75d1e4 100644 --- a/src/editor/utils/index.js +++ b/src/editor/utils/index.js @@ -19,6 +19,9 @@ export const getUniqueId = set => { return id } +export const isOdd = number => Math.abs(number) % 2 === 1 +export const isEven = number => Math.abs(number) % 2 === 0 + // https://github.com/jashkenas/underscore export const throttle = (func, wait = 50) => { let context