Skip to content

Commit 9742f7d

Browse files
committed
fix gfm header link generation with respect to deduplicatedHeaderId
Signed-off-by: hoijui <[email protected]>
1 parent 3d5d8e2 commit 9742f7d

File tree

1 file changed

+69
-19
lines changed

1 file changed

+69
-19
lines changed

public/js/extra.js

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -859,20 +859,45 @@ const anchorForId = id => {
859859
return anchor
860860
}
861861

862+
const createHeaderId = (headerContent, headerIds = null) => {
863+
864+
// to escape characters not allow in css and humanize
865+
const slug = slugifyWithUTF8(headerContent)
866+
let id
867+
if (window.linkifyHeaderStyle === 'keep-case') {
868+
id = slug
869+
} else if (window.linkifyHeaderStyle === 'lower-case') {
870+
// to make compatible with GitHub, GitLab, Pandoc and many more
871+
id = slug.toLowerCase()
872+
} else if (window.linkifyHeaderStyle === 'gfm') {
873+
// see GitHub implementation reference:
874+
// https://gist.github.com/asabaylus/3071099#gistcomment-1593627
875+
// it works like 'lower-case', but ...
876+
const id_base = slug.toLowerCase()
877+
id = id_base
878+
if (headerIds !== null) {
879+
// ... making sure the id is unique
880+
let i = 1
881+
while (headerIds.has(id)) {
882+
id = id_base + '-' + i
883+
i++
884+
}
885+
headerIds.add(id)
886+
}
887+
} else {
888+
throw new Error('Unknown linkifyHeaderStyle value "' + window.linkifyHeaderStyle + '"')
889+
}
890+
return id
891+
}
892+
862893
const linkifyAnchors = (level, containingElement) => {
863894
const headers = containingElement.getElementsByTagName(`h${level}`)
864895

865896
for (let i = 0, l = headers.length; i < l; i++) {
866897
const header = headers[i]
867898
if (header.getElementsByClassName('anchor').length === 0) {
868899
if (typeof header.id === 'undefined' || header.id === '') {
869-
// to escape characters not allow in css and humanize
870-
let id = slugifyWithUTF8(getHeaderContent(header))
871-
// to make compatible with GitHub, GitLab, Pandoc and many more
872-
if (window.linkifyHeaderStyle !== 'keep-case') {
873-
id = id.toLowerCase()
874-
}
875-
header.id = id
900+
header.id = createHeaderId(getHeaderContent(header))
876901
}
877902
if (!(typeof header.id === 'undefined' || header.id === '')) {
878903
header.insertBefore(anchorForId(header.id), header.firstChild)
@@ -898,20 +923,45 @@ function getHeaderContent (header) {
898923
return headerHTML[0].innerHTML
899924
}
900925

926+
function changeHeaderId ($header, id, newId) {
927+
928+
$header.attr('id', newId)
929+
const $headerLink = $header.find(`> a.anchor[href="#${id}"]`)
930+
$headerLink.attr('href', `#${newId}`)
931+
$headerLink.attr('title', newId)
932+
}
933+
901934
export function deduplicatedHeaderId (view) {
935+
936+
// headers contained in the last change
902937
const headers = view.find(':header.raw').removeClass('raw').toArray()
903-
for (let i = 0; i < headers.length; i++) {
904-
const id = $(headers[i]).attr('id')
905-
if (!id) continue
906-
const duplicatedHeaders = view.find(`:header[id="${id}"]`).toArray()
907-
for (let j = 0; j < duplicatedHeaders.length; j++) {
908-
if (duplicatedHeaders[j] !== headers[i]) {
909-
const newId = id + j
910-
const $duplicatedHeader = $(duplicatedHeaders[j])
911-
$duplicatedHeader.attr('id', newId)
912-
const $headerLink = $duplicatedHeader.find(`> a.anchor[href="#${id}"]`)
913-
$headerLink.attr('href', `#${newId}`)
914-
$headerLink.attr('title', newId)
938+
if (headers.length == 0) {
939+
return;
940+
}
941+
if (window.linkifyHeaderStyle === 'gfm') {
942+
// consistent with GitHub, GitLab, Pandoc & co.
943+
// all headers contained in the document, in order of appearance
944+
const allHeaders = view.find(`:header`).toArray()
945+
// list of finaly assigned header IDs
946+
let headerIds = new Set()
947+
for (let j = 0; j < allHeaders.length; j++) {
948+
const $header = $(allHeaders[j])
949+
const id = $header.attr('id')
950+
const newId = createHeaderId(getHeaderContent($header), headerIds)
951+
changeHeaderId($header, id, newId)
952+
}
953+
} else {
954+
// the legacy way
955+
for (let i = 0; i < headers.length; i++) {
956+
const id = $(headers[i]).attr('id')
957+
if (!id) continue
958+
const duplicatedHeaders = view.find(`:header[id="${id}"]`).toArray()
959+
for (let j = 0; j < duplicatedHeaders.length; j++) {
960+
if (duplicatedHeaders[j] !== headers[i]) {
961+
const newId = id + j
962+
const $header = $(duplicatedHeaders[j])
963+
changeHeaderId($header, id, newId)
964+
}
915965
}
916966
}
917967
}

0 commit comments

Comments
 (0)