@@ -859,20 +859,45 @@ const anchorForId = id => {
859
859
return anchor
860
860
}
861
861
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
+
862
893
const linkifyAnchors = ( level , containingElement ) => {
863
894
const headers = containingElement . getElementsByTagName ( `h${ level } ` )
864
895
865
896
for ( let i = 0 , l = headers . length ; i < l ; i ++ ) {
866
897
const header = headers [ i ]
867
898
if ( header . getElementsByClassName ( 'anchor' ) . length === 0 ) {
868
899
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 ) )
876
901
}
877
902
if ( ! ( typeof header . id === 'undefined' || header . id === '' ) ) {
878
903
header . insertBefore ( anchorForId ( header . id ) , header . firstChild )
@@ -898,20 +923,45 @@ function getHeaderContent (header) {
898
923
return headerHTML [ 0 ] . innerHTML
899
924
}
900
925
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
+
901
934
export function deduplicatedHeaderId ( view ) {
935
+
936
+ // headers contained in the last change
902
937
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
+ }
915
965
}
916
966
}
917
967
}
0 commit comments