From ce1ba8289c4e7d0a162ed99750f40a153771514f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 6 Nov 2023 22:30:26 -0600 Subject: [PATCH 01/35] Add Multi-line Dictionary Definition (
) rows. Expands the existing syntax to allow/expect the option of multiple definitions by adding any number of ``` :: Definition``` to an a DT/DD set. --- shared/naturalcrit/markdown.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 114229887..900475986 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -218,8 +218,9 @@ const definitionLists = { while (match = regex.exec(src)) { definitions.push({ dt : this.lexer.inlineTokens(match[1].trim()), - dd : this.lexer.inlineTokens(match[2].trim()) + dd : match[2].split('::').map((s)=>this.lexer.inlineTokens(s.trim())) }); + console.log(match.splice(2).map((s)=>s.trim())); endIndex = regex.lastIndex; } if(definitions.length) { @@ -232,8 +233,9 @@ const definitionLists = { }, renderer(token) { return `
${token.definitions.reduce((html, def)=>{ - return `${html}
${this.parser.parseInline(def.dt)}
` - + `
${this.parser.parseInline(def.dd)}
\n`; + const dds = def.dd.map((s)=>`
${this.parser.parseInline(s)}
`).join('\n'); + return `${html}
${this.parser.parseInline(def.dt)}
+ ${dds}`; }, '')}
`; } }; From e6428a3b18220c30ac2c244a069e4f8118e022f1 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Nov 2023 18:07:11 -0600 Subject: [PATCH 02/35] Update Editor highlighting for Definition Lists Fixes syntax highlighting to account for multiple definitions on a definition list. --- client/homebrew/editor/editor.jsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index b4f1fc824..cf762974e 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -154,9 +154,14 @@ const Editor = createClass({ const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; let match; while ((match = regex.exec(line)) != null){ + codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[0]) }, { line: lineNumber, ch: line.indexOf(match[0]) + match[0].length }, { className: 'define' }); codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[1]) }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length }, { className: 'term' }); - codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[2]) }, { line: lineNumber, ch: line.indexOf(match[2]) + match[2].length }, { className: 'definition' }); + const matches = match[2].split('::').map((s)=>(s.trim())); + matches.forEach((m)=>{ + codeMirror.markText({ line: lineNumber, ch: line.indexOf(m) }, { line: lineNumber, ch: line.indexOf(m) + m.length }, { className: 'definition' }); + }); + // codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[2]) }, { line: lineNumber, ch: line.indexOf(match[2]) + match[2].length }, { className: 'definition' }); } } From d1152dcbb5e825ca16564b2442fac8a263eb997d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 7 Nov 2023 21:04:03 -0600 Subject: [PATCH 03/35] Add Change log --- changelog.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/changelog.md b/changelog.md index 9f4a07ab2..081bd85ea 100644 --- a/changelog.md +++ b/changelog.md @@ -80,6 +80,32 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). +### Tuesday 07/11/2023 + +{{ taskList + +##### abquintic + +* [x] Add user requested feature for definition lists with multiple definitions. + +This implements issue [#2340](https://github.com/naturalcrit/homebrewery/issues/2340) by extending the existing syntax pattern. Additional definitions must be on the same line. + +``` +Dictionary Term :: Definition One :: Definition Two :: Definition Three +``` +Example: +``` +Egg::Came before the Chicken::Python Packaging Format::Over Easy isn't + +Egg + Came before the Chicken + Python Packaging Format + Over Easy isn't +``` + + +}} + ### Friday 13/10/2023 - v3.10.0 {{taskList From 827fdd3cff641c5e171df80a09d10d38cef1844d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 Nov 2023 00:43:45 -0600 Subject: [PATCH 04/35] REmove a console message. --- shared/naturalcrit/markdown.js | 1 - 1 file changed, 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 900475986..ff262b244 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -220,7 +220,6 @@ const definitionLists = { dt : this.lexer.inlineTokens(match[1].trim()), dd : match[2].split('::').map((s)=>this.lexer.inlineTokens(s.trim())) }); - console.log(match.splice(2).map((s)=>s.trim())); endIndex = regex.lastIndex; } if(definitions.length) { From c78dcbfe0563d03321a47ef6688df8eb5811999c Mon Sep 17 00:00:00 2001 From: David Bolack Date: Fri, 10 Nov 2023 23:19:55 -0600 Subject: [PATCH 05/35] Remove Line-break Remove the linbreak between the and the first
--- shared/naturalcrit/markdown.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index ff262b244..ab4a0447f 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -233,8 +233,7 @@ const definitionLists = { renderer(token) { return `
${token.definitions.reduce((html, def)=>{ const dds = def.dd.map((s)=>`
${this.parser.parseInline(s)}
`).join('\n'); - return `${html}
${this.parser.parseInline(def.dt)}
- ${dds}`; + return `${html}
${this.parser.parseInline(def.dt)}
${dds}`; }, '')}
`; } }; From 0624f8a0b962f3b1c8e397d4c4762e1863691e18 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 22 Nov 2023 13:13:58 -0600 Subject: [PATCH 06/35] Add basic tests for Dictionary lists. --- package.json | 1 + tests/markdown/marked-extensions.test.js | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/markdown/marked-extensions.test.js diff --git a/package.json b/package.json index cd2b446ba..2ee0c8c12 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --verbose --noStackTrace", "test:mustache-syntax:block": "jest '.*(mustache-syntax).*' -t '^Block:.*' --verbose --noStackTrace", "test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --verbose --noStackTrace", + "test:marked-extensions": "jest '.*(marked-extensions).*' --verbose --noStackTrace", "test:route": "jest tests/routes/static-pages.test.js --verbose", "phb": "node scripts/phb.js", "prod": "set NODE_ENV=production && npm run build", diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js new file mode 100644 index 000000000..52f2da38f --- /dev/null +++ b/tests/markdown/marked-extensions.test.js @@ -0,0 +1,24 @@ +/* eslint-disable max-lines */ + +const Markdown = require('naturalcrit/markdown.js'); + +describe('Dictionary Terms', ()=>{ + test('Single Definition', function() { + const source = 'My term :: My First Definition'; + const rendered = Markdown.render(source); + 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 rendered = Markdown.render(source); + 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 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
'); + }); + +}); From 96d973528c3fb12bbc46f044b78c0927b79da033 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 20 Dec 2023 22:57:37 -0600 Subject: [PATCH 07/35] Updated and reworked to handle more definition* Updated to allow multiple definition terms and definitions per term :: :::: :: ``` **Example** :: ::V3 uses HTML *definition lists* to create "lists" with hanging indents. ::Three I'm a term::Four **Hello**::I\'m a different ::List : ``` --- shared/naturalcrit/markdown.js | 45 +++++++++++++++--------- tests/markdown/marked-extensions.test.js | 18 ++++++---- themes/V3/5ePHB/style.less | 2 +- 3 files changed, 42 insertions(+), 23 deletions(-) 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; From 993ae295afb42efdb12aa3ec8e8f91b825bee888 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 7 Jan 2024 15:40:05 -0600 Subject: [PATCH 08/35] Update editor pattern match for DLs --- client/homebrew/editor/editor.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index cd74b0af5..ad773c25a 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -151,7 +151,8 @@ const Editor = createClass({ // definition lists if(line.includes('::')){ - const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; + // const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; + const regex = /^([^\n:]*?)::(.*)(?:\n|$)/ym; let match; while ((match = regex.exec(line)) != null){ From 20b76bdeadeca3860cd686d533c50fdd785672b0 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 13 Jan 2024 11:55:43 -0600 Subject: [PATCH 09/35] Fix issue when pattern matches a DD without DT ``` Test ::One ``` WOuld previously break the browser. --- shared/naturalcrit/markdown.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index f016218ba..935313d0f 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -243,17 +243,19 @@ const definitionLists = { let match; const endIndex = src.match(`\n\n`)?.index + 2; const allDefinitions = []; - let currentDefinition = []; + let currentDefinition = {}; while (match = regex.exec(src)) { if(match[1].trim()?.length) { if(currentDefinition?.dt?.length) { allDefinitions.push(currentDefinition); - currentDefinition = []; + currentDefinition = {}; } currentDefinition = { dt : this.lexer.inlineTokens(match[1].trim()), dd : [] }; + } else if(_.isEmpty(currentDefinition)) { + return; } currentDefinition.dd = currentDefinition.dd.concat(match[2].split('::').filter((item)=>item).map((s)=>this.lexer.inlineTokens(s.trim()))); if(!currentDefinition.dd?.length) { @@ -273,7 +275,7 @@ const definitionLists = { let returnVal = `
`; token.definitions.forEach((def)=>{ const dds = def.dd.map((s)=>`
${this.parser.parseInline(s)}
`).join('\n'); - returnVal += `
${this.parser.parseInline(def.dt)}
${dds}
`; + returnVal += `
${this.parser.parseInline(def.dt)}
\n${dds}\n`; }); return `${returnVal}
`; } From d076d6c71999f14476e65baabd9cd229f496447e Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 13 Jan 2024 18:58:59 -0600 Subject: [PATCH 10/35] Update tests for previous changes. --- tests/markdown/marked-extensions.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 5f8c7718e..003934d63 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -6,25 +6,25 @@ describe('Dictionary Terms', ()=>{ test('Single Definition', function() { 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
\n
My First Definition
\n
'); }); test('Two Definitions', function() { 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
\n
My First Definition
\n
My Second Definition
\n
'); }); test('Three Definitions', function() { 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
\n
My First Definition
\n
My Second Definition
\n
My Third Definition
\n
'); }); 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
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
\n
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
Three
\n
Four
\n
Hello
\n
I\’m a different
\n
List
\n
'); }); }); From 4c2211c428fe901597f8d37d8f964f5e07707321 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 14 Jan 2024 13:30:52 -0600 Subject: [PATCH 11/35] Updated rendering to follow input line breaks Updated and additional tests. --- shared/naturalcrit/markdown.js | 15 ++++++++++----- tests/markdown/marked-extensions.test.js | 11 +++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 935313d0f..b434e62b0 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -257,9 +257,12 @@ const definitionLists = { } else if(_.isEmpty(currentDefinition)) { return; } - 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('')]; + const newDefinitions = match[2].split('::').filter((item)=>item).map((s)=>this.lexer.inlineTokens(s.trim())); + console.log(newDefinitions); + if(newDefinitions?.length) { + currentDefinition.dd.push(newDefinitions); + } else { + currentDefinition.dd.push([this.lexer.inlineTokens('')]); } } if(currentDefinition.hasOwnProperty('dt')) { allDefinitions.push(currentDefinition); } @@ -274,8 +277,10 @@ const definitionLists = { renderer(token) { let returnVal = `
`; token.definitions.forEach((def)=>{ - const dds = def.dd.map((s)=>`
${this.parser.parseInline(s)}
`).join('\n'); - returnVal += `
${this.parser.parseInline(def.dt)}
\n${dds}\n`; + const dds = def.dd.map((ddef)=>{ + return ddef.map((s)=>`
${this.parser.parseInline(s)}
`).join(''); + }).join('\n'); + returnVal += `
${this.parser.parseInline(def.dt)}
${dds.indexOf('\n') > -1 ? '\n' : ''}${dds}\n`; }); return `${returnVal}
`; } diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 003934d63..d4446de68 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -6,25 +6,24 @@ describe('Dictionary Terms', ()=>{ test('Single Definition', function() { const source = 'My term :: My First Definition\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
\n
My First Definition
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
\n
'); }); test('Two Definitions', function() { 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
\n
My First Definition
\n
My Second Definition
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
My Second Definition
\n
'); }); test('Three Definitions', function() { 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
\n
My First Definition
\n
My Second Definition
\n
My Third Definition
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
My Second Definition
My Third Definition
\n
'); }); - 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'; + test('Multiple Definition Terms, multiple mixed-line definitions', function() { + const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1::Definition 3 of Term 1\nTerm 2::Definition of Term 2'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
\n
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
Three
\n
Four
\n
Hello
\n
I\’m a different
\n
List
\n
'); }); }); From d09dc11f5f8ac22b7b21877642b822b4b784e088 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 14 Jan 2024 13:38:01 -0600 Subject: [PATCH 12/35] The remainder of the tests --- tests/markdown/marked-extensions.test.js | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index d4446de68..71bb47a30 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -21,9 +21,34 @@ describe('Dictionary Terms', ()=>{ expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
My Second Definition
My Third Definition
\n
'); }); + test('Multiline Definitions', function() { + const source = '**Example** :: V3 uses HTML *definition lists* to create "lists" with hanging indents.\n::Two::\nThree\n::Four\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
\n
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
TwoThree
\n
Four
\n
'); + }); + + test('Multiple Definition Terms, single line, single definition', function() { + const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + }); + + test('Multiple Definition Terms, single line, multiple definitions', function() { + const source = 'Term 1::Definition 1 of Term 1::Definition 2 of Term 1\nTerm 2::Definition 1 of Term 2::Definition 2 of Term 2'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + }); + + test('Multiple Definition Terms, single definitions, multiple lines', function() { + const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1\nTerm 2::Definition of Term 2'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + }); + test('Multiple Definition Terms, multiple mixed-line definitions', function() { const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1::Definition 3 of Term 1\nTerm 2::Definition of Term 2'; const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); }); }); From 0470d13ae011701ddcecb69bb88abcaf847ab941 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 13:03:37 +1300 Subject: [PATCH 13/35] Add optimized NC logo --- themes/assets/naturalCritLogo.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 themes/assets/naturalCritLogo.svg diff --git a/themes/assets/naturalCritLogo.svg b/themes/assets/naturalCritLogo.svg new file mode 100644 index 000000000..88faa64fa --- /dev/null +++ b/themes/assets/naturalCritLogo.svg @@ -0,0 +1 @@ + \ No newline at end of file From fe0cfcb2b6dd29f5365c03ebd31798f391a539b1 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 14:11:07 +1300 Subject: [PATCH 14/35] New file was unnecessary --- themes/assets/naturalCritLogo.svg | 1 - 1 file changed, 1 deletion(-) delete mode 100644 themes/assets/naturalCritLogo.svg diff --git a/themes/assets/naturalCritLogo.svg b/themes/assets/naturalCritLogo.svg deleted file mode 100644 index 88faa64fa..000000000 --- a/themes/assets/naturalCritLogo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From c9c5176f1b6f54b3540bdc9d78859de7d04be18b Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 14:13:01 +1300 Subject: [PATCH 15/35] Add Credits styling to 5ePHB theme --- themes/V3/5ePHB/style.less | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 6c6634ce7..28873c795 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -940,3 +940,28 @@ } } } + +//***************************** +//* CREDITS +//*****************************/ +.page .homebreweryCredits { + font-family: "NodestoCapsWide"; + font-size: .4cm; + line-height: 1em; + color: #FFFFFF; + text-align: center; + text-indent: 0; + letter-spacing: .08em; + } + .page .homebreweryCredits .homebreweryIcon { + margin: 10px auto; + display: block; + height: 75px; + mask: url(/assets/naturalCritLogoWhite.svg) center / contain no-repeat; + -webkit-mask: url(/assets/naturalCritLogoWhite.svg) center / contain no-repeat; + background-color: red; + } + .page .homebreweryCredits .homebreweryIcon.gold { + background-image: linear-gradient(to top left, brown 22.5%, gold 40%, white 60%, gold 67.5%, brown 82.5%); + } + \ No newline at end of file From 2f383d59b611940fe542fbf60c3372804ad01c57 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 14:15:58 +1300 Subject: [PATCH 16/35] Add HB Credit snippet --- themes/V3/5ePHB/snippets.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index c0933d70d..91cbe07b8 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -212,6 +212,21 @@ module.exports = [ }} \n`; }, + }, + { + name : 'Homebrewery Credit', + icon : 'fas fa-dice-d20', + gen : function(){ + return dedent` + {{homebreweryCredits + Made With + + {{homebreweryIcon,gold}} + + Homebrewery.Naturalcrit.com + }} + \n`; + }, } ] }, From d0ccc4a15ac567ed4355d17906ffa7d06cd614e4 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 15:29:46 +1300 Subject: [PATCH 17/35] Capitalize C in NaturalCrit.com --- themes/V3/5ePHB/snippets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index 91cbe07b8..a56d8e979 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -223,7 +223,7 @@ module.exports = [ {{homebreweryIcon,gold}} - Homebrewery.Naturalcrit.com + Homebrewery.NaturalCrit.com }} \n`; }, From 033776168eb03900deee7bf3cd9f715e8d5b8df2 Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 19:52:17 +1300 Subject: [PATCH 18/35] Change the text to include URL link --- themes/V3/5ePHB/snippets.js | 3 ++- themes/V3/5ePHB/style.less | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index a56d8e979..9676647ca 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -223,7 +223,8 @@ module.exports = [ {{homebreweryIcon,gold}} - Homebrewery.NaturalCrit.com + The Homebrewery + [Homebrewery.NaturalCrit.com](https://homebrewery.naturalcrit.com) }} \n`; }, diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 28873c795..3d0c79351 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -948,20 +948,23 @@ font-family: "NodestoCapsWide"; font-size: .4cm; line-height: 1em; - color: #FFFFFF; text-align: center; text-indent: 0; letter-spacing: .08em; - } - .page .homebreweryCredits .homebreweryIcon { +} +.page .homebreweryCredits a { + color: inherit; + text-decoration: none; +} +.page .homebreweryCredits .homebreweryIcon { margin: 10px auto; display: block; height: 75px; mask: url(/assets/naturalCritLogoWhite.svg) center / contain no-repeat; -webkit-mask: url(/assets/naturalCritLogoWhite.svg) center / contain no-repeat; background-color: red; - } - .page .homebreweryCredits .homebreweryIcon.gold { +} +.page .homebreweryCredits .homebreweryIcon.gold { background-image: linear-gradient(to top left, brown 22.5%, gold 40%, white 60%, gold 67.5%, brown 82.5%); - } +} \ No newline at end of file From e56ff93db1601c566efbc90ef1d011fff059484d Mon Sep 17 00:00:00 2001 From: "G.Ambatte" Date: Sun, 1 Oct 2023 19:58:57 +1300 Subject: [PATCH 19/35] Add underline on hover to link in credit --- themes/V3/5ePHB/style.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 3d0c79351..cf5067d41 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -956,6 +956,9 @@ color: inherit; text-decoration: none; } +.page .homebreweryCredits a:hover { + text-decoration: underline; +} .page .homebreweryCredits .homebreweryIcon { margin: 10px auto; display: block; From c0cabbb56383a5458f88a1b775c11f6b19b3cebf Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 15 Jan 2024 21:35:19 -0600 Subject: [PATCH 20/35] Move Credits snippet to Blank --- themes/V3/5ePHB/snippets.js | 16 ---------------- themes/V3/5ePHB/style.less | 31 ------------------------------- 2 files changed, 47 deletions(-) diff --git a/themes/V3/5ePHB/snippets.js b/themes/V3/5ePHB/snippets.js index 9676647ca..c0933d70d 100644 --- a/themes/V3/5ePHB/snippets.js +++ b/themes/V3/5ePHB/snippets.js @@ -212,22 +212,6 @@ module.exports = [ }} \n`; }, - }, - { - name : 'Homebrewery Credit', - icon : 'fas fa-dice-d20', - gen : function(){ - return dedent` - {{homebreweryCredits - Made With - - {{homebreweryIcon,gold}} - - The Homebrewery - [Homebrewery.NaturalCrit.com](https://homebrewery.naturalcrit.com) - }} - \n`; - }, } ] }, diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index cf5067d41..6c6634ce7 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -940,34 +940,3 @@ } } } - -//***************************** -//* CREDITS -//*****************************/ -.page .homebreweryCredits { - font-family: "NodestoCapsWide"; - font-size: .4cm; - line-height: 1em; - text-align: center; - text-indent: 0; - letter-spacing: .08em; -} -.page .homebreweryCredits a { - color: inherit; - text-decoration: none; -} -.page .homebreweryCredits a:hover { - text-decoration: underline; -} -.page .homebreweryCredits .homebreweryIcon { - margin: 10px auto; - display: block; - height: 75px; - mask: url(/assets/naturalCritLogoWhite.svg) center / contain no-repeat; - -webkit-mask: url(/assets/naturalCritLogoWhite.svg) center / contain no-repeat; - background-color: red; -} -.page .homebreweryCredits .homebreweryIcon.gold { - background-image: linear-gradient(to top left, brown 22.5%, gold 40%, white 60%, gold 67.5%, brown 82.5%); -} - \ No newline at end of file From c747c5577e5aeddbe24e15116b6fac57932eb68e Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 16 Jan 2024 02:01:55 -0600 Subject: [PATCH 21/35] Add PANdoc style lists ( using :: not : ) Includes new tests and fixes broken old tests --- shared/naturalcrit/markdown.js | 7 ++-- tests/markdown/marked-extensions.test.js | 51 ++++++++++++++++++------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index c191c081f..8b54ece57 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -239,7 +239,7 @@ const definitionLists = { level : 'block', 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|$)/ym; + const regex = /^([^:\n]*?)[\n]?::(.*)(?:\n|$)/ym; let match; const endIndex = src.match(`\n\n`)?.index + 2; const allDefinitions = []; @@ -258,7 +258,6 @@ const definitionLists = { return; } const newDefinitions = match[2].split('::').filter((item)=>item).map((s)=>this.lexer.inlineTokens(s.trim())); - console.log(newDefinitions); if(newDefinitions?.length) { currentDefinition.dd.push(newDefinitions); } else { @@ -277,11 +276,13 @@ const definitionLists = { renderer(token) { let returnVal = `
`; token.definitions.forEach((def)=>{ - const dds = def.dd.map((ddef)=>{ + let dds = def.dd.map((ddef)=>{ return ddef.map((s)=>`
${this.parser.parseInline(s)}
`).join(''); }).join('\n'); + dds = dds.trim(); returnVal += `
${this.parser.parseInline(def.dt)}
${dds.indexOf('\n') > -1 ? '\n' : ''}${dds}\n`; }); + returnVal = returnVal.trim(); return `${returnVal}
`; } }; diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 71bb47a30..814aea993 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -6,49 +6,74 @@ describe('Dictionary Terms', ()=>{ test('Single Definition', function() { 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
\n
'); + 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\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
My Second Definition
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
My Second Definition
'); }); test('Three Definitions', function() { 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
My Second Definition
My Third Definition
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
My Second Definition
My Third Definition
'); }); test('Multiline Definitions', function() { - const source = '**Example** :: V3 uses HTML *definition lists* to create "lists" with hanging indents.\n::Two::\nThree\n::Four\n\n'; + const source = '**Example** :: V3 uses HTML *definition lists* to create "lists" with hanging indents.\n::Two\n::Three\n::Four\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
\n
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
TwoThree
\n
Four
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
\n
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
Two
\n
Three
\n
Four
'); }); test('Multiple Definition Terms, single line, single definition', function() { - const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2'; + const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); }); test('Multiple Definition Terms, single line, multiple definitions', function() { - const source = 'Term 1::Definition 1 of Term 1::Definition 2 of Term 1\nTerm 2::Definition 1 of Term 2::Definition 2 of Term 2'; + const source = 'Term 1::Definition 1 of Term 1::Definition 2 of Term 1\nTerm 2::Definition 1 of Term 2::Definition 2 of Term 2\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1 of Term 1
Definition 2 of Term 1
\n
Term 2
Definition 1 of Term 2
Definition 2 of Term 2
'); }); test('Multiple Definition Terms, single definitions, multiple lines', function() { - const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1\nTerm 2::Definition of Term 2'; + const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1\nTerm 2::Definition of Term 2\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 of Term 1
\n
Definition 2 of Term 1
\n
Term 2
Definition of Term 2
'); }); test('Multiple Definition Terms, multiple mixed-line definitions', function() { - const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1::Definition 3 of Term 1\nTerm 2::Definition of Term 2'; + const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1::Definition 3 of Term 1\nTerm 2::Definition of Term 2\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2>
Definition of Term 2
\n
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 of Term 1
\n
Definition 2 of Term 1
Definition 3 of Term 1
\n
Term 2
Definition of Term 2
'); }); + test('PANdoc style list - Single Term, Single Definition', function() { + const source = 'Term 1\n::Definition 1\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1
'); + }); + + test('PANdoc style list - Single Term, Plural Definitions', function() { + const source = 'Term 1\n::Definition 1\n::Definition 2\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
'); + }); + + test('PANdoc style list - Multiple Term, Single Definitions', function() { + const source = 'Term 1\n::Definition 1\nTerm 2\n::Definition 1\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1
\n
Term 2
Definition 1
'); + }); + + test('PANdoc style list - Multiple Term, Plural Definitions', function() { + const source = 'Term 1\n::Definition 1\n::Definition 2\nTerm 2\n::Definition 1\n::Definition 2\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
\n
Term 2
\n
Definition 1
\n
Definition 2
'); + }); + + }); From e1ad05eb3a427bf023223e9fa550c50fd61b124e Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 29 Jan 2024 23:42:13 -0600 Subject: [PATCH 22/35] Solve regression with monster template. Was not handling "weak" Definition list endings well ( places were it was \n instead of \n\n. --- shared/naturalcrit/markdown.js | 3 ++- themes/V3/5ePHB/style.less | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 46de16960..151d7e958 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -263,10 +263,11 @@ const definitionLists = { tokenizer(src, tokens) { const regex = /^([^:\n]*?)[\n]?::(.*)(?:\n|$)/ym; let match; - const endIndex = src.match(`\n\n`)?.index + 2; + let endIndex = 0; const allDefinitions = []; let currentDefinition = {}; while (match = regex.exec(src)) { + endIndex += match[0].length; if(match[1].trim()?.length) { if(currentDefinition?.dt?.length) { allDefinitions.push(currentDefinition); diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index ff8bd286c..865cfef5a 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -320,6 +320,30 @@ padding : 0px; margin-bottom : 0.325cm; + dl { + padding: 0px; + } + + dt::before { + display: block; + } + + dt:nth-child(1n+2)::before { + content: ""; + display: block; + } + + dt { + display: inline; + margin-right : 5px; + margin-left : 0em; + padding: 0px; + } + + dd { + display: inline; + } + //Headers h2 { margin : 0; @@ -869,6 +893,8 @@ dl { line-height : 1.25em; & + * { margin-top : 0.17cm; } + white-space: normal !important; + } p + dl { margin-top : 0.17cm; } dt { From 283c2b5ae19d074d74391b769e5841770b425396 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Mon, 5 Feb 2024 21:18:36 -0600 Subject: [PATCH 23/35] Empty Tag multiline input --- shared/naturalcrit/markdown.js | 105 +++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 24 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 151d7e958..b466ec8fb 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -256,41 +256,96 @@ const superSubScripts = { } }; -const definitionLists = { - name : 'definitionLists', +const inlineDefinitionLists = { + name : 'inlineDefinitionLists', // Inline because the styles for *this* set should be display: inline + level : 'block', + start(src) { return src.match(/^.*?::.*/m)?.index; }, // Hint to Marked.js to stop and check for a match + tokenizer(src, tokens) { + const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; + let match; + let endIndex = 0; + const definitions = []; + while (match = regex.exec(src)) { + definitions.push({ + dt : this.lexer.inlineTokens(match[1].trim()), + dd : this.lexer.inlineTokens(match[2].trim()) + }); + endIndex = regex.lastIndex; + } + if(definitions.length) { + return { + type : 'inlineDefinitionLists', + raw : src.slice(0, endIndex), + definitions + }; + } + }, + renderer(token) { + return `
${token.definitions.reduce((html, def)=>{ + return `${html}
${this.parser.parseInline(def.dt)}
` + + `
${this.parser.parseInline(def.dd)}
\n`; + }, '')}
`; + } +}; + +const blockDefinitionLists = { + name : 'blockDefinitionLists', // Block because style display: block level : 'block', 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]?::(.*)(?:\n|$)|^.*(?:\n|$)/ym; let match; let endIndex = 0; const allDefinitions = []; let currentDefinition = {}; + let inList = false; + let lastEmpty = false; while (match = regex.exec(src)) { endIndex += match[0].length; - if(match[1].trim()?.length) { - if(currentDefinition?.dt?.length) { - allDefinitions.push(currentDefinition); - currentDefinition = {}; + if(match[0].indexOf(':') > -1) { + inList = true; + if(match[1].trim()?.length) { + if(currentDefinition?.dt?.length) { + allDefinitions.push(currentDefinition); + currentDefinition = {}; + } + currentDefinition = { + dt : this.lexer.inlineTokens(match[1].trim()), + dd : [], + ddo : [] + }; + } else if(_.isEmpty(currentDefinition)) { + return; + } + const newDefinitions = _.flatten(match[2].split('::').filter((item)=>item).map((s)=>s.trim())); + if(newDefinitions?.length) { + currentDefinition.dd = currentDefinition.dd.concat(newDefinitions); + } else { + currentDefinition.dd.push(''); + } + lastEmpty = false; + } else if(inList) { + if(match[0].trim().length == 0) { + if(lastEmpty) { + break; + } else { + lastEmpty = true; + } + } else { + lastEmpty = false; + currentDefinition.dd[currentDefinition.dd.length - 1] = `${currentDefinition.dd[ currentDefinition.dd.length - 1 ]} ${match[0].trim()}`; } - currentDefinition = { - dt : this.lexer.inlineTokens(match[1].trim()), - dd : [] - }; - } else if(_.isEmpty(currentDefinition)) { - return; - } - const newDefinitions = match[2].split('::').filter((item)=>item).map((s)=>this.lexer.inlineTokens(s.trim())); - if(newDefinitions?.length) { - currentDefinition.dd.push(newDefinitions); - } else { - currentDefinition.dd.push([this.lexer.inlineTokens('')]); } } - if(currentDefinition.hasOwnProperty('dt')) { allDefinitions.push(currentDefinition); } + if(currentDefinition.hasOwnProperty('dt')) { + currentDefinition.dd.forEach((dd)=>{ + currentDefinition.ddo.push(this.lexer.inlineTokens(dd)); + }); + allDefinitions.push(currentDefinition); + } if(allDefinitions.length) { return { - type : 'definitionLists', + type : 'blockDefinitionLists', raw : src.slice(0, endIndex), definitions : allDefinitions }; @@ -299,18 +354,20 @@ const definitionLists = { renderer(token) { let returnVal = `
`; token.definitions.forEach((def)=>{ - let dds = def.dd.map((ddef)=>{ - return ddef.map((s)=>`
${this.parser.parseInline(s)}
`).join(''); + console.log(def.ddo); + let dds = def.ddo.map((s)=>{ + return `
${this.parser.parseInline(s)}
`; }).join('\n'); dds = dds.trim(); returnVal += `
${this.parser.parseInline(def.dt)}
${dds.indexOf('\n') > -1 ? '\n' : ''}${dds}\n`; }); returnVal = returnVal.trim(); + console.log(returnVal); return `${returnVal}
`; } }; -Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts] }); +Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, blockDefinitionLists, superSubScripts] }); Marked.use(mustacheInjectBlock); Marked.use({ renderer: renderer, mangle: false }); Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite()); From 703e207970d1c09b8a8581ec6117d7160c0bcd68 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 6 Feb 2024 21:47:15 -0600 Subject: [PATCH 24/35] I think I have all the desired modes in place. I feel like this is ugly code and maybe there are prettier ways to do it, but it functions as I *believe* is currently desired. --- shared/naturalcrit/markdown.js | 52 ++++++++++++++++++++++++++-------- themes/V3/5ePHB/style.less | 19 +++++++++++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index b466ec8fb..f888cade8 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -300,12 +300,23 @@ const blockDefinitionLists = { let currentDefinition = {}; let inList = false; let lastEmpty = false; + let inlineDefinitions = false; while (match = regex.exec(src)) { + // If we aren't actively in a DL and we match just text, bail. + // If the last loop bailed with lastEmpty and we match just text, bail + if(((!inList) || (lastEmpty)) && (typeof match[1] == 'undefined') && (typeof match[2] == 'undefined')) { + break; + } endIndex += match[0].length; - if(match[0].indexOf(':') > -1) { + // Check to see if this a match containing the start of a DD. + if(match[0].indexOf('::') > -1) { inList = true; - if(match[1].trim()?.length) { + // Check for a DT value. + if(match[1]?.trim()?.length>0) { if(currentDefinition?.dt?.length) { + currentDefinition.dd.forEach((dd)=>{ + currentDefinition.ddo.push(this.lexer.inlineTokens(dd)); + }); allDefinitions.push(currentDefinition); currentDefinition = {}; } @@ -317,23 +328,42 @@ const blockDefinitionLists = { } else if(_.isEmpty(currentDefinition)) { return; } - const newDefinitions = _.flatten(match[2].split('::').filter((item)=>item).map((s)=>s.trim())); - if(newDefinitions?.length) { - currentDefinition.dd = currentDefinition.dd.concat(newDefinitions); + // Test for a DD value. + if(match[2].trim().length>0) { + if((match[1]?.length > 0) && (match[0].indexOf('\n') > match[1]?.length)) { // Inline Style DD + currentDefinition.dd = currentDefinition.dd.concat([match[2].trim()]); + currentDefinition.dd.forEach((dd)=>{ + currentDefinition.ddo.push(this.lexer.inlineTokens(dd)); + }); + allDefinitions.push(currentDefinition); + inlineDefinitions = true; + currentDefinition = {}; + continue; + } + // Multi-line style DDs + const newDefinitions = _.flatten(match[2].split('::').filter((item)=>item).map((s)=>s.trim())); + if(newDefinitions?.length) { + currentDefinition.dd = currentDefinition.dd.concat(newDefinitions); + } } else { currentDefinition.dd.push(''); } lastEmpty = false; - } else if(inList) { + } else if(inList) { // Regular line that might mark the end of a line. + if(inlineDefinitions) { + endIndex -= match[0].length; + break; + } if(match[0].trim().length == 0) { if(lastEmpty) { - break; + continue; } else { lastEmpty = true; } } else { lastEmpty = false; - currentDefinition.dd[currentDefinition.dd.length - 1] = `${currentDefinition.dd[ currentDefinition.dd.length - 1 ]} ${match[0].trim()}`; + const lastPos = typeof currentDefinition.dd.length !== 'undefined' ? currentDefinition.dd.length - 1 : 0; + currentDefinition.dd[lastPos] = `${currentDefinition.dd[lastPos]} ${match[0].trim()}`; } } } @@ -347,22 +377,20 @@ const blockDefinitionLists = { return { type : 'blockDefinitionLists', raw : src.slice(0, endIndex), + inlineDefinitions, definitions : allDefinitions }; } }, renderer(token) { - let returnVal = `
`; + let returnVal = ``; token.definitions.forEach((def)=>{ - console.log(def.ddo); let dds = def.ddo.map((s)=>{ return `
${this.parser.parseInline(s)}
`; }).join('\n'); - dds = dds.trim(); returnVal += `
${this.parser.parseInline(def.dt)}
${dds.indexOf('\n') > -1 ? '\n' : ''}${dds}\n`; }); returnVal = returnVal.trim(); - console.log(returnVal); return `${returnVal}
`; } }; diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 865cfef5a..16a0b1e4f 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -896,7 +896,13 @@ white-space: normal !important; } + + dd { + display: block + } + p + dl { margin-top : 0.17cm; } + dt { display : inline; margin-right : 5px; @@ -904,6 +910,19 @@ } } +// ***************************** +// * Inline Definition Lists +// *****************************/ +.inlineDL dd { + display: inline !important + } + + .inlineDL dd:after{ + display: block; + content: ''; + } + + // ***************************** // * WIDE // *****************************/ From 3ee9fe1c3fa5322d9617c8c87f894568b5203f0a Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 6 Feb 2024 22:13:44 -0600 Subject: [PATCH 25/35] Update tests. Prune no lionger valid cases. --- client/homebrew/editor/editor.jsx | 22 +++++----- client/homebrew/editor/editor.less | 10 +++++ tests/markdown/marked-extensions.test.js | 53 +++++++----------------- 3 files changed, 36 insertions(+), 49 deletions(-) diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index ad773c25a..0d1378439 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -151,21 +151,21 @@ const Editor = createClass({ // definition lists if(line.includes('::')){ - // const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; - const regex = /^([^\n:]*?)::(.*)(?:\n|$)/ym; + if(/^:*$/.test(line) == true){ return }; + const regex = /^([^\n:]*?)(::[^\n]*)(?:\n|$)/ymd; // the `d` flag, for match indices, throws an ESLint error. let match; while ((match = regex.exec(line)) != null){ - - codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[0]) }, { line: lineNumber, ch: line.indexOf(match[0]) + match[0].length }, { className: 'define' }); - codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[1]) }, { line: lineNumber, ch: line.indexOf(match[1]) + match[1].length }, { className: 'term' }); - const matches = match[2].split('::').map((s)=>(s.trim())); - matches.forEach((m)=>{ - codeMirror.markText({ line: lineNumber, ch: line.indexOf(m) }, { line: lineNumber, ch: line.indexOf(m) + m.length }, { className: 'definition' }); - }); - // codeMirror.markText({ line: lineNumber, ch: line.indexOf(match[2]) }, { line: lineNumber, ch: line.indexOf(match[2]) + match[2].length }, { className: 'definition' }); + codeMirror.markText({ line: lineNumber, ch: match.indices[0][0] }, { line: lineNumber, ch: match.indices[0][1] }, { className: 'dl-highlight' }); + codeMirror.markText({ line: lineNumber, ch: match.indices[1][0] }, { line: lineNumber, ch: match.indices[1][1] }, { className: 'dt-highlight' }); + codeMirror.markText({ line: lineNumber, ch: match.indices[2][0] }, { line: lineNumber, ch: match.indices[2][1] }, { className: 'dd-highlight' }); + const ddIndex = match.indices[2][0]; + let colons = /::/g; + let colonMatches; + while((colonMatches = colons.exec(match[2])) !== null){ + codeMirror.markText({ line: lineNumber, ch: colonMatches.index + ddIndex }, { line: lineNumber, ch: colonMatches.index + colonMatches[0].length + ddIndex }, { className: 'dl-colon-highlight'} ) + } } } - // Superscript if(line.includes('\^')) { const regex = /\^(?!\s)(?=([^\n\^]*[^\s\^]))\1\^/g; diff --git a/client/homebrew/editor/editor.less b/client/homebrew/editor/editor.less index b165f91db..d7950ead3 100644 --- a/client/homebrew/editor/editor.less +++ b/client/homebrew/editor/editor.less @@ -55,6 +55,16 @@ vertical-align : sub; font-size : 0.9em; } + .dl-highlight { + &.dl-colon-highlight { + font-weight : bold; + color : #949494; + background : #E5E5E5; + border-radius : 3px; + } + &.dt-highlight { color : rgb(96, 117, 143); } + &.dd-highlight { color : rgb(97, 57, 178); } + } } .brewJump { diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 814aea993..5a8603ab8 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -6,49 +6,13 @@ describe('Dictionary Terms', ()=>{ test('Single Definition', function() { 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
'); - }); - - test('Two Definitions', function() { - 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
My Second Definition
'); - }); - - test('Three Definitions', function() { - 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
My Second Definition
My Third Definition
'); - }); - - test('Multiline Definitions', function() { - const source = '**Example** :: V3 uses HTML *definition lists* to create "lists" with hanging indents.\n::Two\n::Three\n::Four\n\n'; - const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Example
\n
V3 uses HTML definition lists to create “lists” with hanging indents.
\n
Two
\n
Three
\n
Four
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
'); }); test('Multiple Definition Terms, single line, single definition', function() { const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); - }); - - test('Multiple Definition Terms, single line, multiple definitions', function() { - const source = 'Term 1::Definition 1 of Term 1::Definition 2 of Term 1\nTerm 2::Definition 1 of Term 2::Definition 2 of Term 2\n\n'; - const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1 of Term 1
Definition 2 of Term 1
\n
Term 2
Definition 1 of Term 2
Definition 2 of Term 2
'); - }); - - test('Multiple Definition Terms, single definitions, multiple lines', function() { - const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1\nTerm 2::Definition of Term 2\n\n'; - const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 of Term 1
\n
Definition 2 of Term 1
\n
Term 2
Definition of Term 2
'); - }); - - test('Multiple Definition Terms, multiple mixed-line definitions', function() { - const source = 'Term 1::Definition 1 of Term 1\n::Definition 2 of Term 1::Definition 3 of Term 1\nTerm 2::Definition of Term 2\n\n'; - const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 of Term 1
\n
Definition 2 of Term 1
Definition 3 of Term 1
\n
Term 2
Definition of Term 2
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); }); test('PANdoc style list - Single Term, Single Definition', function() { @@ -75,5 +39,18 @@ describe('Dictionary Terms', ()=>{ expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
\n
Term 2
\n
Definition 1
\n
Definition 2
'); }); + test('PANdoc style list - Single Term, Single multiple line definition', function() { + const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1 and more and more and more
'); + + }); + + test('PANdoc style list - Multiple Term, Single multiple line definition', function() { + const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n::Definition 2\n\n::Definition 3\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more and more
\n
Definition 2
\n
Definition 3
'); + + }); }); From 13fbcd0eb1b0991b9fa7798af946287882ddffa1 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 6 Feb 2024 23:29:59 -0600 Subject: [PATCH 26/35] Improve Regex to permit DTs with a final : --- shared/naturalcrit/markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index f888cade8..9d981fd47 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -293,7 +293,7 @@ const blockDefinitionLists = { level : 'block', 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|$)|^.*(?:\n|$)/ym; + const regex = /^([^\n]*?:?)\n?::(.*)(?:\n|$)|^.*(?:\n|$)/ym; let match; let endIndex = 0; const allDefinitions = []; From f3148ed53cb5b283398278585c0d091f1f659565 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Wed, 7 Feb 2024 20:23:19 -0600 Subject: [PATCH 27/35] Fix Syntax Highlighting Update changelog to match PR target shifts. --- changelog.md | 33 ++++++++++++++++++++++--------- client/homebrew/editor/editor.jsx | 4 ++-- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/changelog.md b/changelog.md index 081bd85ea..fe3076059 100644 --- a/changelog.md +++ b/changelog.md @@ -80,7 +80,7 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). -### Tuesday 07/11/2023 +### Tuesday 02/07/2024 {{ taskList @@ -88,22 +88,37 @@ For a full record of development, visit our [Github Page](https://github.com/nat * [x] Add user requested feature for definition lists with multiple definitions. -This implements issue [#2340](https://github.com/naturalcrit/homebrewery/issues/2340) by extending the existing syntax pattern. Additional definitions must be on the same line. +This implements issue [#2340](https://github.com/naturalcrit/homebrewery/issues/2340) by extending the existing syntax pattern. + +Multiple Definition Description (\) terms must go on the following line with a blank line between definition sets. Additionally, Descriptions may be multi-line, if desired. Multi-line descriptions will be concatenated into a single Description on render. + +The previous, inline system has not been removed, however, the two forms may not be intermixed. ``` -Dictionary Term :: Definition One :: Definition Two :: Definition Three +Dictionary Term +:: Definition One +:: Definition Two +:: Definition Three ``` Example: ``` -Egg::Came before the Chicken::Python Packaging Format::Over Easy isn't - Egg - Came before the Chicken - Python Packaging Format - Over Easy isn't +::Came before the Chicken +::Python Packaging Format +::Over +Easy +isn't ``` - +Results: +``` +
+
Egg
+
Came before the Chicken
+
Python Packaging Format
+
Over Easy isn't
+
+``` }} ### Friday 13/10/2023 - v3.10.0 diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 0d1378439..7a5f433f5 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -160,8 +160,8 @@ const Editor = createClass({ codeMirror.markText({ line: lineNumber, ch: match.indices[2][0] }, { line: lineNumber, ch: match.indices[2][1] }, { className: 'dd-highlight' }); const ddIndex = match.indices[2][0]; let colons = /::/g; - let colonMatches; - while((colonMatches = colons.exec(match[2])) !== null){ + let colonMatches = colons.exec(match[2]); + if(colonMatches !== null){ codeMirror.markText({ line: lineNumber, ch: colonMatches.index + ddIndex }, { line: lineNumber, ch: colonMatches.index + colonMatches[0].length + ddIndex }, { className: 'dl-colon-highlight'} ) } } From 2b81c26cffb38c76cce3cdf78becf70d2144569f Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 8 Feb 2024 19:23:33 -0600 Subject: [PATCH 28/35] Working, but ugly --- shared/naturalcrit/markdown.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 9d981fd47..46b1ff59e 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -301,6 +301,7 @@ const blockDefinitionLists = { let inList = false; let lastEmpty = false; let inlineDefinitions = false; + let appending = false; while (match = regex.exec(src)) { // If we aren't actively in a DL and we match just text, bail. // If the last loop bailed with lastEmpty and we match just text, bail @@ -308,9 +309,17 @@ const blockDefinitionLists = { break; } endIndex += match[0].length; + // Check to see if this a match containing the start of a DD. if(match[0].indexOf('::') > -1) { inList = true; + // Check and see if we are currently in line appending mode + if(appending) { + const lastPos = typeof currentDefinition.dd.length !== 'undefined' ? currentDefinition.dd.length - 1 : 0; + currentDefinition.dd[lastPos] = `${currentDefinition.dd[lastPos]} ${match[1]?.trim()}`; + match[1] = ''; + } + appending = false; // Check for a DT value. if(match[1]?.trim()?.length>0) { if(currentDefinition?.dt?.length) { @@ -341,7 +350,7 @@ const blockDefinitionLists = { continue; } // Multi-line style DDs - const newDefinitions = _.flatten(match[2].split('::').filter((item)=>item).map((s)=>s.trim())); + const newDefinitions = _.flatten(match[2].split('\n::').filter((item)=>item).map((s)=>s.trim())); if(newDefinitions?.length) { currentDefinition.dd = currentDefinition.dd.concat(newDefinitions); } @@ -364,6 +373,7 @@ const blockDefinitionLists = { lastEmpty = false; const lastPos = typeof currentDefinition.dd.length !== 'undefined' ? currentDefinition.dd.length - 1 : 0; currentDefinition.dd[lastPos] = `${currentDefinition.dd[lastPos]} ${match[0].trim()}`; + appending = true; } } } From 67b11d62ea20f63e65a64ef2e1690da6b4df4635 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Thu, 8 Feb 2024 19:35:43 -0600 Subject: [PATCH 29/35] Small DD appending mode fix --- shared/naturalcrit/markdown.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 46b1ff59e..5289dd645 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -313,7 +313,8 @@ const blockDefinitionLists = { // Check to see if this a match containing the start of a DD. if(match[0].indexOf('::') > -1) { inList = true; - // Check and see if we are currently in line appending mode + // Check and see if we are currently in line appending mode, if so, match[1] should be + // appended to the last entry instead of being used as the next DT. if(appending) { const lastPos = typeof currentDefinition.dd.length !== 'undefined' ? currentDefinition.dd.length - 1 : 0; currentDefinition.dd[lastPos] = `${currentDefinition.dd[lastPos]} ${match[1]?.trim()}`; @@ -359,6 +360,7 @@ const blockDefinitionLists = { } lastEmpty = false; } else if(inList) { // Regular line that might mark the end of a line. + appending = false; if(inlineDefinitions) { endIndex -= match[0].length; break; From 05f88dfd0070f08109a52f68dcc7da6904921730 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sun, 25 Feb 2024 09:19:31 -0600 Subject: [PATCH 30/35] Extended Definition List cleanup Remove redundant inlineBlock extension Add missing trim on multiline definitions Fix editor regex for colon terminated terms. --- changelog.md | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/changelog.md b/changelog.md index 8bc8719e7..e86c2ea0f 100644 --- a/changelog.md +++ b/changelog.md @@ -84,49 +84,6 @@ pre { ## changelog For a full record of development, visit our [Github Page](https://github.com/naturalcrit/homebrewery). -<<<<<<< HEAD -### Tuesday 02/07/2024 - -{{ taskList - -##### abquintic - -* [x] Add user requested feature for definition lists with multiple definitions. - -This implements issue [#2340](https://github.com/naturalcrit/homebrewery/issues/2340) by extending the existing syntax pattern. - -Multiple Definition Description (\) terms must go on the following line with a blank line between definition sets. Additionally, Descriptions may be multi-line, if desired. Multi-line descriptions will be concatenated into a single Description on render. - -The previous, inline system has not been removed, however, the two forms may not be intermixed. - -``` -Dictionary Term -:: Definition One -:: Definition Two -:: Definition Three -``` -Example: -``` -Egg -::Came before the Chicken -::Python Packaging Format -::Over -Easy -isn't -``` - -Results: -``` -
-
Egg
-
Came before the Chicken
-
Python Packaging Format
-
Over Easy isn't
-
-``` -}} - -======= ### Wednesday 21/2/2024 - v3.11.0 {{taskList @@ -300,7 +257,6 @@ There are $[TableNum] tables in this document. *(note: final value of `$[TableNu \page ->>>>>>> master ### Friday 13/10/2023 - v3.10.0 {{taskList From f6c0b0d6fc0a3351c394dd1a175e3a3828b43d01 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 7 Mar 2024 23:46:10 -0500 Subject: [PATCH 31/35] Simplification of CSS --- package.json | 2 +- shared/naturalcrit/markdown.js | 8 ++-- tests/markdown/marked-extensions.test.js | 15 +++----- themes/V3/5ePHB/style.less | 48 +----------------------- 4 files changed, 12 insertions(+), 61 deletions(-) diff --git a/package.json b/package.json index 972d82138..8cee4082a 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "test:mustache-syntax:inline": "jest '.*(mustache-syntax).*' -t '^Inline:.*' --verbose --noStackTrace", "test:mustache-syntax:block": "jest '.*(mustache-syntax).*' -t '^Block:.*' --verbose --noStackTrace", "test:mustache-syntax:injection": "jest '.*(mustache-syntax).*' -t '^Injection:.*' --verbose --noStackTrace", - "test:marked-extensions": "jest '.*(marked-extensions).*' --verbose --noStackTrace", + "test:marked-extensions": "jest tests/markdown/marked-extensions.test.js --verbose --noStackTrace", "test:route": "jest tests/routes/static-pages.test.js --verbose", "phb": "node scripts/phb.js", "prod": "set NODE_ENV=production && npm run build", diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 227b9ad35..defd4100e 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -401,12 +401,12 @@ const definitionLists = { } }, renderer(token) { - let returnVal = ``; + let returnVal = `
`; token.definitions.forEach((def)=>{ let dds = def.ddo.map((s)=>{ - return `
${this.parser.parseInline(s).trim()}
`; - }).join('\n'); - returnVal += `
${this.parser.parseInline(def.dt)}
${dds.indexOf('\n') > -1 ? '\n' : ''}${dds}\n`; + return `${token.inlineDefinitions ? '' : '\n'}
${this.parser.parseInline(s).trim()}
`; + }).join(''); + returnVal += `
${this.parser.parseInline(def.dt)}
${dds}\n`; }); returnVal = returnVal.trim(); return `${returnVal}
`; diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 5a8603ab8..6d3be056f 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -2,23 +2,23 @@ const Markdown = require('naturalcrit/markdown.js'); -describe('Dictionary Terms', ()=>{ +describe('Definition Terms', ()=>{ test('Single Definition', function() { 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('Multiple Definition Terms, single line, single definition', function() { const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); }); test('PANdoc style list - Single Term, Single Definition', function() { const source = 'Term 1\n::Definition 1\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
'); }); test('PANdoc style list - Single Term, Plural Definitions', function() { @@ -30,7 +30,7 @@ describe('Dictionary Terms', ()=>{ test('PANdoc style list - Multiple Term, Single Definitions', function() { const source = 'Term 1\n::Definition 1\nTerm 2\n::Definition 1\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1
\n
Term 2
Definition 1
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Term 2
\n
Definition 1
'); }); test('PANdoc style list - Multiple Term, Plural Definitions', function() { @@ -42,15 +42,12 @@ describe('Dictionary Terms', ()=>{ test('PANdoc style list - Single Term, Single multiple line definition', function() { const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition 1 and more and more and more
'); - + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more and more
'); }); test('PANdoc style list - Multiple Term, Single multiple line definition', function() { const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n::Definition 2\n\n::Definition 3\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more and more
\n
Definition 2
\n
Definition 3
'); - }); - }); diff --git a/themes/V3/5ePHB/style.less b/themes/V3/5ePHB/style.less index 50cb5c977..ed3e8604c 100644 --- a/themes/V3/5ePHB/style.less +++ b/themes/V3/5ePHB/style.less @@ -319,30 +319,6 @@ padding : 0px; margin-bottom : 0.325cm; - dl { - padding: 0px; - } - - dt::before { - display: block; - } - - dt:nth-child(1n+2)::before { - content: ""; - display: block; - } - - dt { - display: inline; - margin-right : 5px; - margin-left : 0em; - padding: 0px; - } - - dd { - display: inline; - } - //Headers h2 { margin : 0; @@ -886,36 +862,14 @@ dl { line-height : 1.25em; & + * { margin-top : 0.17cm; } - white-space: normal !important; - } - - dd { - display: block - } - p + dl { margin-top : 0.17cm; } - - dt { - display : inline; + dt { margin-right : 5px; margin-left : -1em; } } -// ***************************** -// * Inline Definition Lists -// *****************************/ -.inlineDL dd { - display: inline !important - } - - .inlineDL dd:after{ - display: block; - content: ''; - } - - // ***************************** // * WIDE // *****************************/ From e36a638ae588dcf04eee6676023e2984949f788d Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Sat, 9 Mar 2024 16:41:05 -0500 Subject: [PATCH 32/35] Add more tests --- tests/markdown/marked-extensions.test.js | 34 +++++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index 6d3be056f..b4e5dee5c 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -2,52 +2,60 @@ const Markdown = require('naturalcrit/markdown.js'); -describe('Definition Terms', ()=>{ - test('Single Definition', function() { +describe('Inline Definition Lists', ()=>{ + test('Single Definition Term', function() { 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
'); }); - test('Multiple Definition Terms, single line, single definition', function() { + test('Multiple Definition Terms', function() { const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); }); +}); - test('PANdoc style list - Single Term, Single Definition', function() { +describe('Multiline Definition Lists', ()=>{ + test('Single Term, Single Definition', function() { const source = 'Term 1\n::Definition 1\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
'); }); - test('PANdoc style list - Single Term, Plural Definitions', function() { + test('Single Term, Plural Definitions', function() { const source = 'Term 1\n::Definition 1\n::Definition 2\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
'); }); - test('PANdoc style list - Multiple Term, Single Definitions', function() { - const source = 'Term 1\n::Definition 1\nTerm 2\n::Definition 1\n\n'; + test('Multiple Term, Single Definitions', function() { + const source = 'Term 1\n::Definition 1\n\nTerm 2\n::Definition 1\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Term 2
\n
Definition 1
'); }); - test('PANdoc style list - Multiple Term, Plural Definitions', function() { - const source = 'Term 1\n::Definition 1\n::Definition 2\nTerm 2\n::Definition 1\n::Definition 2\n\n'; + test('Multiple Term, Plural Definitions', function() { + const source = 'Term 1\n::Definition 1\n::Definition 2\n\nTerm 2\n::Definition 1\n::Definition 2\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
\n
Term 2
\n
Definition 1
\n
Definition 2
'); }); - test('PANdoc style list - Single Term, Single multiple line definition', function() { + test('Single Term, Single multi-line definition', function() { const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n'; const rendered = Markdown.render(source); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more and more
'); }); - test('PANdoc style list - Multiple Term, Single multiple line definition', function() { - const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n::Definition 2\n\n::Definition 3\n\n'; + test('Single Term, Plural multi-line definitions', function() { + const source = 'Term 1\n::Definition 1\nand more and more\n::Definition 2\n\n::Definition 3\n\n'; const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more and more
\n
Definition 2
\n
Definition 3
'); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Definition 2
\n
Definition 3
'); + }); + + test('Multiple Term, Single multi-line definition', function() { + const source = 'Term 1\n::Definition 1\nand more and more\n\nTerm 2\n::Definition 1\n\n::Definition 2\n\n'; + const rendered = Markdown.render(source); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Term 2
\n
Definition 1
\n
Definition 2
'); }); }); From f3b17f46154105a36158171c3e3a834e9527bedc Mon Sep 17 00:00:00 2001 From: David Bolack Date: Sat, 9 Mar 2024 19:40:54 -0600 Subject: [PATCH 33/35] Fix bad merge --- shared/naturalcrit/markdown.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 227b9ad35..6c9cdc5cb 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -413,8 +413,6 @@ const definitionLists = { } }; -Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts] }); - //v=====--------------------< Variable Handling >-------------------=====v// 242 lines const replaceVar = function(input, hoist=false, allowUnresolved=false) { const regex = /([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]/g; @@ -660,7 +658,7 @@ function MarkedVariables() { //^=====--------------------< Variable Handling >-------------------=====^// Marked.use(MarkedVariables()); -Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, superSubScripts] }); +Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts] }); Marked.use(mustacheInjectBlock); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite()); From d7756230fb3dc58ac27138d9dbe5a9c6f7d49d53 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 14 Mar 2024 00:02:18 -0400 Subject: [PATCH 34/35] More tests. Split into two extensions Split into two extensions as single-line and multiline are different syntaxes. Simplified a lot of logic and probably cleaner as their own NPM packages (eventually). --- shared/naturalcrit/markdown.js | 153 ++++++++--------------- tests/markdown/marked-extensions.test.js | 44 +++++-- 2 files changed, 86 insertions(+), 111 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 4bc14e19a..01fdbac96 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -294,117 +294,74 @@ const superSubScripts = { } }; -const definitionLists = { - name : 'definitionLists', // Block because style display: block +const definitionListsInline = { + name : 'definitionListsInline', level : 'block', - start(src) { return src.match(/^.*?::.*\n\n/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|$)|^.*(?:\n|$)/ym; + const regex = /^([^\n]*?)::([^\n]*)(?:\n|$)/ym; let match; let endIndex = 0; - const allDefinitions = []; - let currentDefinition = {}; - let inList = false; - let lastEmpty = false; - let inlineDefinitions = false; - let appending = false; + const definitions = []; while (match = regex.exec(src)) { - // If we aren't actively in a DL and we match just text, bail. - // If the last loop bailed with lastEmpty and we match just text, bail - if(((!inList) || (lastEmpty)) && (typeof match[1] == 'undefined') && (typeof match[2] == 'undefined')) { - break; - } - endIndex += match[0].length; - - // Check to see if this a match containing the start of a DD. - if(match[0].indexOf('::') > -1) { - inList = true; - // Check and see if we are currently in line appending mode, if so, match[1] should be - // appended to the last entry instead of being used as the next DT. - if(appending) { - const lastPos = typeof currentDefinition.dd.length !== 'undefined' ? currentDefinition.dd.length - 1 : 0; - currentDefinition.dd[lastPos] = `${currentDefinition.dd[lastPos]} ${match[1]?.trim()}`; - match[1] = ''; - } - appending = false; - // Check for a DT value. - if(match[1]?.trim()?.length>0) { - if(currentDefinition?.dt?.length) { - currentDefinition.dd.forEach((dd)=>{ - currentDefinition.ddo.push(this.lexer.inlineTokens(dd)); - }); - allDefinitions.push(currentDefinition); - currentDefinition = {}; - } - currentDefinition = { - dt : this.lexer.inlineTokens(match[1].trim()), - dd : [], - ddo : [] - }; - } else if(_.isEmpty(currentDefinition)) { - return; - } - // Test for a DD value. - if(match[2].trim().length>0) { - if((match[1]?.length > 0) && (match[0].indexOf('\n') > match[1]?.length)) { // Inline Style DD - currentDefinition.dd = currentDefinition.dd.concat([match[2].trim()]); - currentDefinition.dd.forEach((dd)=>{ - currentDefinition.ddo.push(this.lexer.inlineTokens(dd)); - }); - allDefinitions.push(currentDefinition); - inlineDefinitions = true; - currentDefinition = {}; - continue; - } - // Multi-line style DDs - const newDefinitions = _.flatten(match[2].split('\n::').filter((item)=>item).map((s)=>s.trim())); - if(newDefinitions?.length) { - currentDefinition.dd = currentDefinition.dd.concat(newDefinitions); - } - } else { - currentDefinition.dd.push(''); - } - lastEmpty = false; - } else if(inList) { // Regular line that might mark the end of a line. - appending = false; - if(inlineDefinitions) { - endIndex -= match[0].length; - break; - } - if(match[0].trim().length == 0) { - if(lastEmpty) { - continue; - } else { - lastEmpty = true; - } - } else { - lastEmpty = false; - const lastPos = typeof currentDefinition.dd.length !== 'undefined' ? currentDefinition.dd.length - 1 : 0; - currentDefinition.dd[lastPos] = `${currentDefinition.dd[lastPos]} ${match[0].trim()}`; - appending = true; - } - } - } - if(currentDefinition.hasOwnProperty('dt')) { - currentDefinition.dd.forEach((dd)=>{ - currentDefinition.ddo.push(this.lexer.inlineTokens(dd)); + definitions.push({ + dt : this.lexer.inlineTokens(match[1].trim()), + dd : this.lexer.inlineTokens(match[2].trim()) }); - allDefinitions.push(currentDefinition); + endIndex = regex.lastIndex; } - if(allDefinitions.length) { + if(definitions.length) { return { - type : 'definitionLists', - raw : src.slice(0, endIndex), - inlineDefinitions, - definitions : allDefinitions + type : 'definitionListsInline', + raw : src.slice(0, endIndex), + definitions + }; + } + }, + renderer(token) { + return `
${token.definitions.reduce((html, def)=>{ + return `${html}
${this.parser.parseInline(def.dt)}
` + + `
${this.parser.parseInline(def.dd)}
`; + }, '')}
`; + } +}; + +const definitionListsMultiline = { + name : 'definitionListsMultiline', + level : 'block', + 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]+?(?=\n::))|\n::(.(?:.|\n)*?(?=(?:\n::)|(?:\n\n)|$))/y; + let match; + let endIndex = 0; + const definitions = []; + while (match = regex.exec(src)) { + if(match[1]) { + definitions.push({ + dt : this.lexer.inlineTokens(match[1].trim()), + dds : [] + }); + } + if(match[2]) { + definitions[definitions.length - 1].dds.push( + this.lexer.inlineTokens(match[2].trim().replace(/\s/g,' ')) + ) + } + endIndex = regex.lastIndex; + } + if(definitions.length) { + return { + type : 'definitionListsMultiline', + raw : src.slice(0, endIndex), + definitions }; } }, renderer(token) { let returnVal = `
`; token.definitions.forEach((def)=>{ - let dds = def.ddo.map((s)=>{ - return `${token.inlineDefinitions ? '' : '\n'}
${this.parser.parseInline(s).trim()}
`; + let dds = def.dds.map((s)=>{ + return `\n
${this.parser.parseInline(s).trim()}
`; }).join(''); returnVal += `
${this.parser.parseInline(def.dt)}
${dds}\n`; }); @@ -658,7 +615,7 @@ function MarkedVariables() { //^=====--------------------< Variable Handling >-------------------=====^// Marked.use(MarkedVariables()); -Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts] }); +Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionListsInline, definitionListsMultiline, superSubScripts] }); Marked.use(mustacheInjectBlock); Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false }); Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite()); diff --git a/tests/markdown/marked-extensions.test.js b/tests/markdown/marked-extensions.test.js index b4e5dee5c..8d6c3c1c4 100644 --- a/tests/markdown/marked-extensions.test.js +++ b/tests/markdown/marked-extensions.test.js @@ -3,59 +3,77 @@ const Markdown = require('naturalcrit/markdown.js'); describe('Inline Definition Lists', ()=>{ + test('No Term 1 Definition', function() { + const source = ':: My First Definition\n\n'; + const rendered = Markdown.render(source).trim(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My First Definition
'); + }); + test('Single Definition Term', function() { const source = 'My term :: My First Definition\n\n'; - const rendered = Markdown.render(source); + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
My term
My First Definition
'); }); test('Multiple Definition Terms', function() { const source = 'Term 1::Definition of Term 1\nTerm 2::Definition of Term 2\n\n'; - const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
\n
Term 2
Definition of Term 2
'); + const rendered = Markdown.render(source).trim(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
Definition of Term 1
Term 2
Definition of Term 2
'); }); }); describe('Multiline Definition Lists', ()=>{ test('Single Term, Single Definition', function() { const source = 'Term 1\n::Definition 1\n\n'; - const rendered = Markdown.render(source); + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
'); }); test('Single Term, Plural Definitions', function() { const source = 'Term 1\n::Definition 1\n::Definition 2\n\n'; - const rendered = Markdown.render(source); + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
'); }); test('Multiple Term, Single Definitions', function() { const source = 'Term 1\n::Definition 1\n\nTerm 2\n::Definition 1\n\n'; - const rendered = Markdown.render(source); + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Term 2
\n
Definition 1
'); }); test('Multiple Term, Plural Definitions', function() { const source = 'Term 1\n::Definition 1\n::Definition 2\n\nTerm 2\n::Definition 1\n::Definition 2\n\n'; - const rendered = Markdown.render(source); + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1
\n
Definition 2
\n
Term 2
\n
Definition 1
\n
Definition 2
'); }); test('Single Term, Single multi-line definition', function() { const source = 'Term 1\n::Definition 1\nand more and\nmore and more\n\n'; - const rendered = Markdown.render(source); + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more and more
'); }); test('Single Term, Plural multi-line definitions', function() { - const source = 'Term 1\n::Definition 1\nand more and more\n::Definition 2\n\n::Definition 3\n\n'; - const rendered = Markdown.render(source); - expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Definition 2
\n
Definition 3
'); + const source = 'Term 1\n::Definition 1\nand more and more\n::Definition 2\nand more\nand more\n::Definition 3\n\n'; + const rendered = Markdown.render(source).trim(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Definition 2 and more and more
\n
Definition 3
'); }); test('Multiple Term, Single multi-line definition', function() { - const source = 'Term 1\n::Definition 1\nand more and more\n\nTerm 2\n::Definition 1\n\n::Definition 2\n\n'; - const rendered = Markdown.render(source); + const source = 'Term 1\n::Definition 1\nand more and more\n\nTerm 2\n::Definition 1\n::Definition 2\n\n'; + const rendered = Markdown.render(source).trim(); expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Term 2
\n
Definition 1
\n
Definition 2
'); }); + + test('Multiple Term, Single multi-line definition, followed by an inline dl', function() { + const source = 'Term 1\n::Definition 1\nand more and more\n\nTerm 2\n::Definition 1\n::Definition 2\n\n::Inline Definition (no term)'; + const rendered = Markdown.render(source).trim(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Term 2
\n
Definition 1
\n
Definition 2
Inline Definition (no term)
'); + }); + + test('Multiple Term, Single multi-line definition, followed by paragraph', function() { + const source = 'Term 1\n::Definition 1\nand more and more\n\nTerm 2\n::Definition 1\n::Definition 2\n\nParagraph'; + const rendered = Markdown.render(source).trim(); + expect(rendered, `Input:\n${source}`, { showPrefix: false }).toBe('
Term 1
\n
Definition 1 and more and more
\n
Term 2
\n
Definition 1
\n
Definition 2

Paragraph

'); + }); }); From f37da196496dbbaa25bf0d6a97fc4fa6232c5c18 Mon Sep 17 00:00:00 2001 From: Trevor Buckner Date: Thu, 14 Mar 2024 00:03:28 -0400 Subject: [PATCH 35/35] lint --- shared/naturalcrit/markdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 01fdbac96..f82ec3c32 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -344,8 +344,8 @@ const definitionListsMultiline = { } if(match[2]) { definitions[definitions.length - 1].dds.push( - this.lexer.inlineTokens(match[2].trim().replace(/\s/g,' ')) - ) + this.lexer.inlineTokens(match[2].trim().replace(/\s/g, ' ')) + ); } endIndex = regex.lastIndex; } @@ -360,7 +360,7 @@ const definitionListsMultiline = { renderer(token) { let returnVal = `
`; token.definitions.forEach((def)=>{ - let dds = def.dds.map((s)=>{ + const dds = def.dds.map((s)=>{ return `\n
${this.parser.parseInline(s).trim()}
`; }).join(''); returnVal += `
${this.parser.parseInline(def.dt)}
${dds}\n`;