From 15e427e806716b372f7fbef12d922f847ccc71b5 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Fri, 27 May 2016 08:22:22 -0400 Subject: PLT-1458 Updated list autonumbering (#3126) * Removed MattermostLexer since it was exactly the same as the default marked one * Updated list autonumbering to always start numbering from the first item's number --- tests/test-markdown-lists.md | 85 ++++++------ webapp/package.json | 2 +- webapp/utils/markdown.jsx | 309 ++----------------------------------------- 3 files changed, 52 insertions(+), 344 deletions(-) diff --git a/tests/test-markdown-lists.md b/tests/test-markdown-lists.md index 7d080526a..355cff021 100644 --- a/tests/test-markdown-lists.md +++ b/tests/test-markdown-lists.md @@ -3,32 +3,32 @@ Verify that all list types render as expected. ### Single-item Ordered List -**Expected:** +**Expected:** ``` 7. Single Item ``` -**Actual:** +**Actual:** 7. Single Item -### Multi-item Ordered List +### Multi-item Ordered List -**Expected:** +**Expected:** ``` 1. One 2. Two 3. Three ``` -**Actual:** +**Actual:** -3. One -2. Two -1. Three +1. One +1. Two +1. Three ### Nested Ordered List -**Expected:** +**Expected:** ``` 1. Alpha 1. Bravo @@ -38,42 +38,42 @@ Verify that all list types render as expected. 2. Foxtrot ``` -**Actual:** +**Actual:** 1. Alpha - 1. Bravo -1. Charlie -1. Delta - 1. Echo - 1. Foxtrot + 1. Bravo +1. Charlie +1. Delta + 1. Echo + 1. Foxtrot ### Single-item Unordered List -**Expected:** +**Expected:** ``` • Single Item ``` -**Actual:** +**Actual:** * Single Item ### Multi-item Unordered List -**Expected:** +**Expected:** ``` • One • Two • Three ``` -**Actual:** +**Actual:** * One - Two + Three ### Nested Unordered List -**Expected:** +**Expected:** ``` • Alpha • Bravo @@ -83,7 +83,7 @@ Verify that all list types render as expected. • Foxtrot ``` -**Actual:** +**Actual:** + Alpha * Bravo - Charlie @@ -93,36 +93,36 @@ Verify that all list types render as expected. ### Mixed List Starting Ordered -**Expected:** +**Expected:** ``` 1. One 2. Two 3. Three ``` -**Actual:** +**Actual:** -1. One -+ Two -- Three +1. One ++ Two +- Three ### Mixed List Starting Unordered -**Expected:** +**Expected:** ``` • Monday • Tuesday • Wednesday ``` -**Actual:** +**Actual:** + Monday 1. Tuesday * Wednesday ### Nested Mixed List -**Expected:** +**Expected:** ``` • Alpha 1. Bravo @@ -142,7 +142,7 @@ Verify that all list types render as expected. 1. Papa ``` -**Actual:** +**Actual:** - Alpha 1. Bravo * Charlie @@ -152,8 +152,8 @@ Verify that all list types render as expected. + Golf 1. Hotel - India - 2. Juliet - 3. Kilo + 1. Juliet + 2. Kilo * Lima 1. Mike 1. November @@ -162,7 +162,7 @@ Verify that all list types render as expected. ### Ordered Lists Separated by Carriage Returns -**Expected:** +**Expected:* ``` 1. One • Two @@ -171,25 +171,25 @@ Verify that all list types render as expected. 2. Two ``` -**Actual:** +**Actual:** 1. One - - Two - - + - Two + + 1. One 2. Two ### Carriage Return and New Line After a List -**Expected:** +**Expected:** ``` 1. One - Two This text should be on a new line. ``` -**Actual:** +**Actual:** 1. One - Two @@ -205,7 +205,7 @@ List: This line should have a line break above it. ``` -**Actual:** +**Actual:** List: @@ -225,7 +225,7 @@ This line should have a line break above it. [x] Completed item ``` -**Actual:** +**Actual:** - [ ] One - [ ] Subpoint one @@ -242,9 +242,8 @@ This line should have a line break above it. 3. [x] Completed item ``` -**Actual:** +**Actual:** 1. [ ] One 2. [ ] Two 3. [x] Completed item - diff --git a/webapp/package.json b/webapp/package.json index 370603dac..deecbc1a8 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -16,7 +16,7 @@ "jasny-bootstrap": "3.1.3", "jquery": "2.2.3", "keymirror": "0.1.1", - "marked": "mattermost/marked#6d1f9d1da95a2ae8d5f7dfb0c9071e53052a3532", + "marked": "mattermost/marked#a16c38a3c7cdaaefc33922812b42bdf8bcfaa127", "match-at": "0.1.0", "mattermost": "mattermost/mattermost-javascript#master", "match-at": "0.1.0", diff --git a/webapp/utils/markdown.jsx b/webapp/utils/markdown.jsx index 69b18faee..18d5cf128 100644 --- a/webapp/utils/markdown.jsx +++ b/webapp/utils/markdown.jsx @@ -120,14 +120,20 @@ class MattermostMarkdownRenderer extends marked.Renderer { return `
${header}${body}
`; } - listitem(text) { + listitem(text, bullet) { const taskListReg = /^\[([ |xX])\] /; const isTaskList = taskListReg.exec(text); if (isTaskList) { return `
  • ${' '}${text.replace(taskListReg, '')}
  • `; } - return `
  • ${text}
  • `; + + if (/^\d+.$/.test(bullet)) { + // this is a numbered list item so override the numbering + return `
  • ${text}
  • `; + } else { + return `
  • ${text}
  • `; + } } text(txt) { @@ -135,301 +141,6 @@ class MattermostMarkdownRenderer extends marked.Renderer { } } -class MattermostLexer extends marked.Lexer { - token(originalSrc, top, bq) { - let src = originalSrc.replace(/^ +$/gm, ''); - - while (src) { - // newline - let cap = this.rules.newline.exec(src); - if (cap) { - src = src.substring(cap[0].length); - if (cap[0].length > 1) { - this.tokens.push({ - type: 'space' - }); - } - } - - // code - cap = this.rules.code.exec(src); - if (cap) { - src = src.substring(cap[0].length); - cap = cap[0].replace(/^ {4}/gm, ''); - this.tokens.push({ - type: 'code', - text: this.options.pedantic ? cap : cap.replace(/\n+$/, '') - }); - continue; - } - - // fences (gfm) - cap = this.rules.fences.exec(src); - if (cap) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'code', - lang: cap[2], - text: cap[3] || '' - }); - continue; - } - - // heading - cap = this.rules.heading.exec(src); - if (cap) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'heading', - depth: cap[1].length, - text: cap[2] - }); - continue; - } - - // table no leading pipe (gfm) - cap = this.rules.nptable.exec(src); - if (top && cap) { - src = src.substring(cap[0].length); - - const item = { - type: 'table', - header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3].replace(/\n$/, '').split('\n') - }; - - for (let i = 0; i < item.align.length; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - for (let i = 0; i < item.cells.length; i++) { - item.cells[i] = item.cells[i].split(/ *\| */); - } - - this.tokens.push(item); - - continue; - } - - // lheading - cap = this.rules.lheading.exec(src); - if (cap) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'heading', - depth: cap[2] === '=' ? 1 : 2, - text: cap[1] - }); - continue; - } - - // hr - cap = this.rules.hr.exec(src); - if (cap) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'hr' - }); - continue; - } - - // blockquote - cap = this.rules.blockquote.exec(src); - if (cap) { - src = src.substring(cap[0].length); - - this.tokens.push({ - type: 'blockquote_start' - }); - - cap = cap[0].replace(/^ *> ?/gm, ''); - - // Pass `top` to keep the current - // "toplevel" state. This is exactly - // how markdown.pl works. - this.token(cap, top, true); - - this.tokens.push({ - type: 'blockquote_end' - }); - - continue; - } - - // list - cap = this.rules.list.exec(src); - if (cap) { - src = src.substring(cap[0].length); - const bull = cap[2]; - - this.tokens.push({ - type: 'list_start', - ordered: bull.length > 1 - }); - - // Get each top-level item. - cap = cap[0].match(this.rules.item); - - let next = false; - const l = cap.length; - let i = 0; - - for (; i < l; i++) { - let item = cap[i]; - - // Remove the list item's bullet - // so it is seen as the next token. - let space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) +/, ''); - - // Outdent whatever the - // list item contains. Hacky. - if (~item.indexOf('\n ')) { - space -= item.length; - item = this.options.pedantic ? - item.replace(/^ {1,4}/gm, '') : - item.replace(new RegExp('^ {1,' + space + '}', 'gm'), ''); - } - - // Determine whether the next list item belongs here. - // Backpedal if it does not belong in this list. - if (this.options.smartLists && i !== l - 1) { - const b = this.rules.bullet.exec(cap[i + 1])[0]; - if (bull !== b && !(bull.length > 1 && b.length > 1)) { - src = cap.slice(i + 1).join('\n') + src; - i = l - 1; - } - } - - // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - let loose = next || (/\n\n(?!\s*$)/).test(item); - if (i !== l - 1) { - next = item.charAt(item.length - 1) === '\n'; - if (!loose) { - loose = next; - } - } - - this.tokens.push({ - type: loose ? - 'loose_item_start' : - 'list_item_start' - }); - - // Recurse. - this.token(item, false, bq); - - this.tokens.push({ - type: 'list_item_end' - }); - } - - this.tokens.push({ - type: 'list_end' - }); - - continue; - } - - // html - cap = this.rules.html.exec(src); - if (cap) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: this.options.sanitize ? 'paragraph' : 'html', - pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), - text: cap[0] - }); - continue; - } - - // def - cap = this.rules.def.exec(src); - if ((!bq && top) && cap) { - src = src.substring(cap[0].length); - this.tokens.links[cap[1].toLowerCase()] = { - href: cap[2], - title: cap[3] - }; - continue; - } - - // table (gfm) - cap = this.rules.table.exec(src); - if (top && cap) { - src = src.substring(cap[0].length); - - const item = { - type: 'table', - header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') - }; - - for (let i = 0; i < item.align.length; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - for (let i = 0; i < item.cells.length; i++) { - item.cells[i] = item.cells[i].replace(/^ *\| *| *\| *$/g, '').split(/ *\| */); - } - - this.tokens.push(item); - - continue; - } - - // top-level paragraph - cap = this.rules.paragraph.exec(src); - if (top && cap) { - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'paragraph', - text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1] - }); - continue; - } - - // text - cap = this.rules.text.exec(src); - if (cap) { - // Top-level should never reach here. - src = src.substring(cap[0].length); - this.tokens.push({ - type: 'text', - text: cap[0] - }); - continue; - } - - if (src) { - throw new Error('Infinite loop on byte: ' + src.charCodeAt(0)); - } - } - - return this.tokens; - } -} - export function format(text, options) { const markdownOptions = { renderer: new MattermostMarkdownRenderer(null, options), @@ -438,9 +149,7 @@ export function format(text, options) { tables: true }; - const tokens = new MattermostLexer(markdownOptions).lex(text); - - return new marked.Parser(markdownOptions).parse(tokens); + return marked(text, markdownOptions); } // Marked helper functions that should probably just be exported -- cgit v1.2.3-1-g7c22