diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 1fc14b534..7a584a927 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -237,32 +237,45 @@ const superSubScripts = { const definitionLists = { name : 'definitionLists', level : 'block', - start(src) { return src.match(/^.*?::.*/m)?.index; }, // Hint to Marked.js to stop and check for a match + start(src) { return src.match(/^.*?::.*\n\n/m)?.index; }, // Hint to Marked.js to stop and check for a match tokenizer(src, tokens) { - const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; + const regex = /^([^\n:]*?)::(.*)(?:\n|$)/ym; let match; - let endIndex = 0; - const definitions = []; + const endIndex = src.match(`\n\n`)?.index + 2; + const allDefinitions = []; + let currentDefinition = []; while (match = regex.exec(src)) { - definitions.push({ - dt : this.lexer.inlineTokens(match[1].trim()), - dd : match[2].split('::').map((s)=>this.lexer.inlineTokens(s.trim())) - }); - endIndex = regex.lastIndex; + if(match[1].trim()?.length) { + if(currentDefinition?.dt?.length) { + allDefinitions.push(currentDefinition); + currentDefinition = []; + } + currentDefinition = { + dt : this.lexer.inlineTokens(match[1].trim()), + dd : [] + }; + } + currentDefinition.dd = currentDefinition.dd.concat(match[2].split('::').filter((item)=>item).map((s)=>this.lexer.inlineTokens(s.trim()))); + if(!currentDefinition.dd?.length) { + currentDefinition.dd = [this.lexer.inlineTokens('')]; + } } - if(definitions.length) { + if(currentDefinition.hasOwnProperty('dt')) { allDefinitions.push(currentDefinition); } + if(allDefinitions.length) { return { - type : 'definitionLists', - raw : src.slice(0, endIndex), - definitions + type : 'definitionLists', + raw : src.slice(0, endIndex), + definitions : allDefinitions }; } }, renderer(token) { - return `
${token.definitions.reduce((html, def)=>{ + let returnVal = `
`; + token.definitions.forEach((def)=>{ const dds = def.dd.map((s)=>`
${this.parser.parseInline(s)}
`).join('\n'); - return `${html}
${this.parser.parseInline(def.dt)}
${dds}`; - }, '')}
`; + returnVal += `
${this.parser.parseInline(def.dt)}
${dds}
`; + }); + return `${returnVal}
`; } }; diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 52f2da38f..5f8c7718e 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -4,21 +4,27 @@ const Markdown = require('naturalcrit/markdown.js'); describe('Dictionary Terms', ()=>{ test('Single Definition', function() { - const source = 'My term :: My First Definition'; + const source = 'My term :: My First Definition\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
'); }); test('Two Definitions', function() { - const source = 'My term :: My First Definition :: My Second Definition'; + const source = 'My term :: My First Definition :: My Second Definition\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
\n
My Second Definition
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
\n
My Second Definition
'); }); test('Three Definitions', function() { - const source = 'My term :: My First Definition :: My Second Definition :: My Third Definition'; + const source = 'My term :: My First Definition :: My Second Definition :: My Third Definition\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
\n
My Second Definition
\n
My Third Definition
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
\n
My Second Definition
\n
My Third Definition
'); + }); + + test('Multiline Definitions', function() { + const source = '**Example** :: V3 uses HTML *definition lists* to create "lists" with hanging indents.\n::Three\n::Four\n\nHello::I\'m a different\n::List\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
Three
\n
Four
Hello
I\’m a different
\n
List
'); }); }); diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 2a2c49772..fbb00c670 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -968,7 +968,7 @@ body { counter-reset : phb-page-numbers; } & + * { margin-top : 0.17cm; } } p + dl { margin-top : 0.17cm; } - dt { + dt { display : inline; margin-right : 5px; margin-left : -1em;