@@ -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+
862893const 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+
901934export 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