From bfe42bc9adc29d6d56e36c8ef71c3948a934552c Mon Sep 17 00:00:00 2001 From: hvarany Date: Fri, 21 Jul 2023 12:54:05 +0400 Subject: [PATCH 1/6] feat(docs): Add functions for generating header IDs and anchor links This commit adds the `generateHeadersIds` and `generateAnchors` functions to the MDRenderer class. These functions are responsible for generating header IDs and anchor links in the rendered markdown content. --- pages/11ty/markdown.shortcut.js | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js index 536e89654..8a9cfac7e 100644 --- a/pages/11ty/markdown.shortcut.js +++ b/pages/11ty/markdown.shortcut.js @@ -27,6 +27,9 @@ class MDRenderer { endAnchorElement.remove(); } + //Add headers ids + MDRenderer.generateHeadersIds(window.document.body); + // Resolve content links MDRenderer.resolveLinks(window.document.body, filePath); @@ -71,6 +74,41 @@ class MDRenderer { } return github.srcUrl + linkPath; } + + static generateHeadersIds(content) { + const headerTags = ['h1', 'h2', 'h3', 'h4']; + const idLengthLimit = 20; + + headerTags.forEach(tag => { + const headers = content.getElementsByTagName(tag); + + for (let header of headers) { + const text = header.textContent; + const id = text + .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase())) + .replace(/[^\w\s]|_/g, "").replace(/\s+/g, "") + .substring(0, idLengthLimit); + + header.setAttribute('id', id); + + this.generateAnchors(content, text, `#${id}`) + } + }); + return content; + } + + static generateAnchors(content, text, link) { + const matches = Array.from(content.querySelectorAll('*')) + .filter(element => element.textContent.includes(text) || element.textContent.includes(text.replace(/_/g, " "))); + const regex = new RegExp(`(^|\\s)${text}(\\s|[,\\.])`, 'g'); + + matches.forEach(match => { + if (!['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(match.tagName)) { + match.innerHTML = match.innerHTML.replace(regex, `$1${text}$2`); + } + }); + } + } module.exports = (config) => { From c8bb7d9947d39b2ffcb1e749d20d1365b3073b06 Mon Sep 17 00:00:00 2001 From: hvarany Date: Fri, 21 Jul 2023 12:58:57 +0400 Subject: [PATCH 2/6] feat(docs): Add function to generate links for globally defined terms This commit adds the `generateGloballyDefinedTermsLinks` function to the MDRenderer class. This function generates links for globally defined terms --- pages/11ty/markdown.shortcut.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js index 8a9cfac7e..532fc1352 100644 --- a/pages/11ty/markdown.shortcut.js +++ b/pages/11ty/markdown.shortcut.js @@ -30,6 +30,9 @@ class MDRenderer { //Add headers ids MDRenderer.generateHeadersIds(window.document.body); + // Add globally defined terms links + MDRenderer.generateGloballyDefinedTermsLinks(window.document.body); + // Resolve content links MDRenderer.resolveLinks(window.document.body, filePath); @@ -97,6 +100,18 @@ class MDRenderer { return content; } + static generateGloballyDefinedTermsLinks (content) { + const globallyDefinedTerms = { + ESL_Base_Element: 'https://esl-ui.com/core/esl-base-element/', + ESL_Mixin_Element: 'https://esl-ui.com/core/esl-mixin-element/' + // Add other globally defined terms as needed + }; + + Object.keys(globallyDefinedTerms).forEach(term => { + this.generateAnchors(content, term.replace(/_/g, " "), globallyDefinedTerms[term]); + }); + } + static generateAnchors(content, text, link) { const matches = Array.from(content.querySelectorAll('*')) .filter(element => element.textContent.includes(text) || element.textContent.includes(text.replace(/_/g, " "))); From 5447d56567ac58834c1461ac572b72f0dc6a38a4 Mon Sep 17 00:00:00 2001 From: hvarany Date: Wed, 2 Aug 2023 16:50:06 +0400 Subject: [PATCH 3/6] feat(docs): Reworked links auto generation according pull request remarks This commit separates functionality for different methods, adjusts Regex --- pages/11ty/markdown.shortcut.js | 87 +++++++++++++++++---------------- pages/site.yml | 4 ++ 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js index 532fc1352..fbb6a57c9 100644 --- a/pages/11ty/markdown.shortcut.js +++ b/pages/11ty/markdown.shortcut.js @@ -5,13 +5,15 @@ const color = require('kleur'); const {JSDOM} = require('jsdom'); const {markdown} = require('./markdown.lib'); -const {github, rewriteRules, urlPrefix} = require('./site.config'); +const {github, rewriteRules, urlPrefix, globalTerms} = require('./site.config'); class MDRenderer { static async render(filePath, startAnchor, endAnchor) { try { const content = await MDRenderer.parseFile(filePath); const {window} = new JSDOM(content); + const localTerms = MDRenderer.generateHeadersIds(window.document.body); + const terms = Object.assign({}, globalTerms, localTerms); // Exclude part before start anchor if (startAnchor) { @@ -27,11 +29,8 @@ class MDRenderer { endAnchorElement.remove(); } - //Add headers ids - MDRenderer.generateHeadersIds(window.document.body); - - // Add globally defined terms links - MDRenderer.generateGloballyDefinedTermsLinks(window.document.body); + // Add anchors and globally defined terms links + MDRenderer.fillReferenceLinks(window.document,window.document.body, terms); // Resolve content links MDRenderer.resolveLinks(window.document.body, filePath); @@ -79,51 +78,53 @@ class MDRenderer { } static generateHeadersIds(content) { - const headerTags = ['h1', 'h2', 'h3', 'h4']; - const idLengthLimit = 20; - - headerTags.forEach(tag => { - const headers = content.getElementsByTagName(tag); - - for (let header of headers) { - const text = header.textContent; - const id = text - .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase())) - .replace(/[^\w\s]|_/g, "").replace(/\s+/g, "") - .substring(0, idLengthLimit); - - header.setAttribute('id', id); - - this.generateAnchors(content, text, `#${id}`) - } - }); - return content; + const headers = [...content.querySelectorAll('h1, h2, h3, h4')]; + const localTerms = new Map(); + for (let header of headers) { + const text = header.textContent; + const id = MDRenderer.createIDFromText(text) + header.setAttribute('id', id); + let anchor = `#${id}` + localTerms.set(text, anchor); + } + return localTerms + } + static createIDFromText(text, idLengthLimit = 20) { + return text + .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase())) + .replace(/[^\w\s]|_/g, "").replace(/\s+/g, "") + .substring(0, idLengthLimit); } - static generateGloballyDefinedTermsLinks (content) { - const globallyDefinedTerms = { - ESL_Base_Element: 'https://esl-ui.com/core/esl-base-element/', - ESL_Mixin_Element: 'https://esl-ui.com/core/esl-mixin-element/' - // Add other globally defined terms as needed - }; - - Object.keys(globallyDefinedTerms).forEach(term => { - this.generateAnchors(content, term.replace(/_/g, " "), globallyDefinedTerms[term]); - }); + static findTextNodes(root) { + let all = []; + for (let node = root.firstChild; node; node = node.nextSibling) { + if (node.nodeType === 3) all.push(node); + else all = all.concat(MDRenderer.findTextNodes(node)); + } + return all } - static generateAnchors(content, text, link) { - const matches = Array.from(content.querySelectorAll('*')) - .filter(element => element.textContent.includes(text) || element.textContent.includes(text.replace(/_/g, " "))); - const regex = new RegExp(`(^|\\s)${text}(\\s|[,\\.])`, 'g'); + static fillReferenceLinks(document, content, terms) { + const nodes = MDRenderer.findTextNodes(content) + .filter((node) => !node.parentElement.closest('h1, h2, h3, h4, h5, h6')) - matches.forEach(match => { - if (!['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(match.tagName)) { - match.innerHTML = match.innerHTML.replace(regex, `$1${text}$2`); + for (const [text, link] of Object.entries(terms)) { + + for (const node of nodes) { + if (node.textContent.includes(text)) { + MDRenderer.replaceTextNode(document, node, text, link) + } } - }); + } } + static replaceTextNode(document, node, text, link) { + const wrapper = document.createElement('span'); + const regex = new RegExp(`(^|\\s)${text}(,?\\s|\\.?\\s)`, 'g'); + wrapper.innerHTML = node.textContent.replace(regex, `$1${text}$2`); + return node.replaceWith(...wrapper.childNodes); + } } module.exports = (config) => { diff --git a/pages/site.yml b/pages/site.yml index 102039c0d..547ce19d6 100644 --- a/pages/site.yml +++ b/pages/site.yml @@ -17,3 +17,7 @@ rewriteRules: "src/modules/esl-traversing-query/README.md": "/core/esl-traversing-query" "src/modules/esl-trigger/README.md": "/components/esl-trigger" "src/modules/esl-toggleable/README.md": "/components/esl-toggleable" + +globalTerms: + "ESL Base Element": "/core/esl-base-element" + "ESL Mixin Element": "/core/esl-mixin-element" From ff1b2bc32dfb4b0d8734fb70103452e6a58f971d Mon Sep 17 00:00:00 2001 From: hvarany Date: Fri, 4 Aug 2023 10:15:48 +0400 Subject: [PATCH 4/6] feat(docs): Fix variables usage, rename method This commit put in order code according project code style guide --- pages/11ty/markdown.shortcut.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js index fbb6a57c9..d47c74102 100644 --- a/pages/11ty/markdown.shortcut.js +++ b/pages/11ty/markdown.shortcut.js @@ -80,11 +80,11 @@ class MDRenderer { static generateHeadersIds(content) { const headers = [...content.querySelectorAll('h1, h2, h3, h4')]; const localTerms = new Map(); - for (let header of headers) { + for (const header of headers) { const text = header.textContent; const id = MDRenderer.createIDFromText(text) header.setAttribute('id', id); - let anchor = `#${id}` + const anchor = `#${id}` localTerms.set(text, anchor); } return localTerms @@ -97,10 +97,10 @@ class MDRenderer { } static findTextNodes(root) { - let all = []; + const all = []; for (let node = root.firstChild; node; node = node.nextSibling) { if (node.nodeType === 3) all.push(node); - else all = all.concat(MDRenderer.findTextNodes(node)); + else all.push(...MDRenderer.findTextNodes(node)); } return all } @@ -113,13 +113,13 @@ class MDRenderer { for (const node of nodes) { if (node.textContent.includes(text)) { - MDRenderer.replaceTextNode(document, node, text, link) + MDRenderer.wrapTextNode(document, node, text, link) } } } } - static replaceTextNode(document, node, text, link) { + static wrapTextNode(document, node, text, link) { const wrapper = document.createElement('span'); const regex = new RegExp(`(^|\\s)${text}(,?\\s|\\.?\\s)`, 'g'); wrapper.innerHTML = node.textContent.replace(regex, `$1${text}$2`); From e7691012688779b2fc5579386f1ab9f3f6e487d4 Mon Sep 17 00:00:00 2001 From: hvarany Date: Thu, 31 Aug 2023 14:22:29 +0400 Subject: [PATCH 5/6] feat(docs): fix object assign changes according PR review --- pages/11ty/markdown.shortcut.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js index d47c74102..922fd1b48 100644 --- a/pages/11ty/markdown.shortcut.js +++ b/pages/11ty/markdown.shortcut.js @@ -30,7 +30,7 @@ class MDRenderer { } // Add anchors and globally defined terms links - MDRenderer.fillReferenceLinks(window.document,window.document.body, terms); + MDRenderer.fillReferenceLinks(window.document, window.document.body, terms); // Resolve content links MDRenderer.resolveLinks(window.document.body, filePath); @@ -79,20 +79,22 @@ class MDRenderer { static generateHeadersIds(content) { const headers = [...content.querySelectorAll('h1, h2, h3, h4')]; - const localTerms = new Map(); + const localTerms = {}; for (const header of headers) { const text = header.textContent; const id = MDRenderer.createIDFromText(text) header.setAttribute('id', id); const anchor = `#${id}` - localTerms.set(text, anchor); + localTerms[text] = anchor; } return localTerms } static createIDFromText(text, idLengthLimit = 20) { return text - .replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase())) - .replace(/[^\w\s]|_/g, "").replace(/\s+/g, "") + .replace(/[^a-zA-Z0-9]+/g, ' ') + .toLowerCase() + .replace(/(?:^|\s)\w/g, (symbol, index) => (index === 0 ? symbol : symbol.toUpperCase())) + .replace(/\s/g, '') .substring(0, idLengthLimit); } @@ -121,9 +123,8 @@ class MDRenderer { static wrapTextNode(document, node, text, link) { const wrapper = document.createElement('span'); - const regex = new RegExp(`(^|\\s)${text}(,?\\s|\\.?\\s)`, 'g'); - wrapper.innerHTML = node.textContent.replace(regex, `$1${text}$2`); - return node.replaceWith(...wrapper.childNodes); + wrapper.innerHTML = node.textContent.replace(text, `${text}`); + node.replaceWith(...wrapper.childNodes); } } From 98f0f118189102086b8fc2cc85de73037a35f453 Mon Sep 17 00:00:00 2001 From: hvarany Date: Tue, 26 Sep 2023 11:01:23 +0400 Subject: [PATCH 6/6] feat(docs): changes according review add missed semicolons --- pages/11ty/markdown.shortcut.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js index 922fd1b48..2a76bb259 100644 --- a/pages/11ty/markdown.shortcut.js +++ b/pages/11ty/markdown.shortcut.js @@ -84,10 +84,10 @@ class MDRenderer { const text = header.textContent; const id = MDRenderer.createIDFromText(text) header.setAttribute('id', id); - const anchor = `#${id}` + const anchor = `#${id}`; localTerms[text] = anchor; } - return localTerms + return localTerms; } static createIDFromText(text, idLengthLimit = 20) { return text @@ -104,18 +104,18 @@ class MDRenderer { if (node.nodeType === 3) all.push(node); else all.push(...MDRenderer.findTextNodes(node)); } - return all + return all; } static fillReferenceLinks(document, content, terms) { const nodes = MDRenderer.findTextNodes(content) - .filter((node) => !node.parentElement.closest('h1, h2, h3, h4, h5, h6')) + .filter((node) => !node.parentElement.closest('h1, h2, h3, h4, h5, h6')); for (const [text, link] of Object.entries(terms)) { for (const node of nodes) { if (node.textContent.includes(text)) { - MDRenderer.wrapTextNode(document, node, text, link) + MDRenderer.wrapTextNode(document, node, text, link); } } }