From 3be40b23d11ddded3f5bf8430dc2084e46563f11 Mon Sep 17 00:00:00 2001 From: hoijui Date: Tue, 29 Oct 2019 09:58:59 +0100 Subject: fix gfm header link generation with respect to `deduplicatedHeaderId` Signed-off-by: hoijui --- public/js/extra.js | 88 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 19 deletions(-) (limited to 'public/js/extra.js') diff --git a/public/js/extra.js b/public/js/extra.js index d381576f..810d6146 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -825,6 +825,37 @@ const anchorForId = id => { return anchor } +const createHeaderId = (headerContent, headerIds = null) => { + + // to escape characters not allow in css and humanize + const slug = slugifyWithUTF8(headerContent) + let id + if (window.linkifyHeaderStyle === 'keep-case') { + id = slug + } else if (window.linkifyHeaderStyle === 'lower-case') { + // to make compatible with GitHub, GitLab, Pandoc and many more + id = slug.toLowerCase() + } else if (window.linkifyHeaderStyle === 'gfm') { + // see GitHub implementation reference: + // https://gist.github.com/asabaylus/3071099#gistcomment-1593627 + // it works like 'lower-case', but ... + const id_base = slug.toLowerCase() + id = id_base + if (headerIds !== null) { + // ... making sure the id is unique + let i = 1 + while (headerIds.has(id)) { + id = id_base + '-' + i + i++ + } + headerIds.add(id) + } + } else { + throw new Error('Unknown linkifyHeaderStyle value "' + window.linkifyHeaderStyle + '"') + } + return id +} + const linkifyAnchors = (level, containingElement) => { const headers = containingElement.getElementsByTagName(`h${level}`) @@ -832,13 +863,7 @@ const linkifyAnchors = (level, containingElement) => { let header = headers[i] if (header.getElementsByClassName('anchor').length === 0) { if (typeof header.id === 'undefined' || header.id === '') { - // to escape characters not allow in css and humanize - let id = slugifyWithUTF8(getHeaderContent(header)) - // to make compatible with GitHub, GitLab, Pandoc and many more - if (window.linkifyHeaderStyle !== 'keep-case') { - id = id.toLowerCase() - } - header.id = id + header.id = createHeaderId(getHeaderContent(header)) } if (!(typeof header.id === 'undefined' || header.id === '')) { header.insertBefore(anchorForId(header.id), header.firstChild) @@ -864,20 +889,45 @@ function getHeaderContent (header) { return headerHTML[0].innerHTML } +function changeHeaderId ($header, id, newId) { + + $header.attr('id', newId) + const $headerLink = $header.find(`> a.anchor[href="#${id}"]`) + $headerLink.attr('href', `#${newId}`) + $headerLink.attr('title', newId) +} + export function deduplicatedHeaderId (view) { + + // headers contained in the last change const headers = view.find(':header.raw').removeClass('raw').toArray() - for (let i = 0; i < headers.length; i++) { - const id = $(headers[i]).attr('id') - if (!id) continue - const duplicatedHeaders = view.find(`:header[id="${id}"]`).toArray() - for (let j = 0; j < duplicatedHeaders.length; j++) { - if (duplicatedHeaders[j] !== headers[i]) { - const newId = id + j - const $duplicatedHeader = $(duplicatedHeaders[j]) - $duplicatedHeader.attr('id', newId) - const $headerLink = $duplicatedHeader.find(`> a.anchor[href="#${id}"]`) - $headerLink.attr('href', `#${newId}`) - $headerLink.attr('title', newId) + if (headers.length == 0) { + return; + } + if (window.linkifyHeaderStyle === 'gfm') { + // consistent with GitHub, GitLab, Pandoc & co. + // all headers contained in the document, in order of appearance + const allHeaders = view.find(`:header`).toArray() + // list of finaly assigned header IDs + let headerIds = new Set() + for (let j = 0; j < allHeaders.length; j++) { + const $header = $(allHeaders[j]) + const id = $header.attr('id') + const newId = createHeaderId(getHeaderContent($header), headerIds) + changeHeaderId($header, id, newId) + } + } else { + // the legacy way + for (let i = 0; i < headers.length; i++) { + const id = $(headers[i]).attr('id') + if (!id) continue + const duplicatedHeaders = view.find(`:header[id="${id}"]`).toArray() + for (let j = 0; j < duplicatedHeaders.length; j++) { + if (duplicatedHeaders[j] !== headers[i]) { + const newId = id + j + const $header = $(duplicatedHeaders[j]) + changeHeaderId($header, id, newId) + } } } } -- cgit v1.2.3 From 3233a448c6cd7f4636daf4008fe8b98d288219d0 Mon Sep 17 00:00:00 2001 From: hoijui Date: Tue, 29 Oct 2019 11:57:51 +0100 Subject: make `headerIds` `const` [fix] Signed-off-by: hoijui --- public/js/extra.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'public/js/extra.js') diff --git a/public/js/extra.js b/public/js/extra.js index 810d6146..23944a17 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -909,7 +909,7 @@ export function deduplicatedHeaderId (view) { // all headers contained in the document, in order of appearance const allHeaders = view.find(`:header`).toArray() // list of finaly assigned header IDs - let headerIds = new Set() + const headerIds = new Set() for (let j = 0; j < allHeaders.length; j++) { const $header = $(allHeaders[j]) const id = $header.attr('id') -- cgit v1.2.3 From ad1a2fb19c842ea5e4cb46a24989ce95b2041902 Mon Sep 17 00:00:00 2001 From: hoijui Date: Tue, 29 Oct 2019 13:20:18 +0100 Subject: make standard conform [fix] Signed-off-by: hoijui --- public/js/extra.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'public/js/extra.js') diff --git a/public/js/extra.js b/public/js/extra.js index 23944a17..6cda6171 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -826,7 +826,6 @@ const anchorForId = id => { } const createHeaderId = (headerContent, headerIds = null) => { - // to escape characters not allow in css and humanize const slug = slugifyWithUTF8(headerContent) let id @@ -839,13 +838,13 @@ const createHeaderId = (headerContent, headerIds = null) => { // see GitHub implementation reference: // https://gist.github.com/asabaylus/3071099#gistcomment-1593627 // it works like 'lower-case', but ... - const id_base = slug.toLowerCase() - id = id_base + const idBase = slug.toLowerCase() + id = idBase if (headerIds !== null) { // ... making sure the id is unique let i = 1 while (headerIds.has(id)) { - id = id_base + '-' + i + id = idBase + '-' + i i++ } headerIds.add(id) @@ -890,7 +889,6 @@ function getHeaderContent (header) { } function changeHeaderId ($header, id, newId) { - $header.attr('id', newId) const $headerLink = $header.find(`> a.anchor[href="#${id}"]`) $headerLink.attr('href', `#${newId}`) @@ -898,11 +896,10 @@ function changeHeaderId ($header, id, newId) { } export function deduplicatedHeaderId (view) { - // headers contained in the last change const headers = view.find(':header.raw').removeClass('raw').toArray() - if (headers.length == 0) { - return; + if (headers.length === 0) { + return } if (window.linkifyHeaderStyle === 'gfm') { // consistent with GitHub, GitLab, Pandoc & co. -- cgit v1.2.3