1
- $ ( function ( ) {
2
- var doc = $ ( document ) ;
3
-
4
- // top link
5
- $ ( '#top' ) . click ( function ( e ) {
6
- $ ( 'html, body' ) . animate ( { scrollTop : 0 } , 500 ) ;
7
- return false ;
8
- } ) ;
1
+ const languageElement = document . getElementById ( 'languageData' ) ;
2
+ const languagesData = languageElement ? JSON . parse ( languageElement . dataset . languages ) : [ ] ;
3
+ const langDisplay = document . getElementById ( 'current-lang' ) ;
4
+ const i18nMsgBox = document . getElementById ( "i18n-notice-box" ) ;
5
+ const scrollToTopBtn = document . getElementById ( "top" ) ;
6
+
7
+ // display current language in language picker component
8
+ if ( langDisplay ) {
9
+ const currentLanguage = window . location . pathname . split ( '/' ) [ 1 ] ;
10
+ const matchedLang = languagesData . find ( lang => lang . code === currentLanguage ) ;
11
+ langDisplay . textContent = matchedLang ? matchedLang . name : 'English' ;
12
+ }
9
13
10
- // scrolling links
11
- var added ;
12
- doc . scroll ( function ( e ) {
13
- if ( doc . scrollTop ( ) > 5 ) {
14
- if ( added ) return ;
15
- added = true ;
16
- $ ( 'body' ) . addClass ( 'scroll' ) ;
17
- } else {
18
- $ ( 'body' ) . removeClass ( 'scroll' ) ;
19
- added = false ;
20
- }
14
+ // scroll to top of the page
15
+ if ( scrollToTopBtn ) {
16
+ scrollToTopBtn . addEventListener ( "click" , function ( e ) {
17
+ e . preventDefault ( ) ;
18
+ window . scrollTo ( {
19
+ top : 0 ,
20
+ behavior : "smooth"
21
+ } )
21
22
} )
23
+ }
22
24
23
- // menu bar
24
-
25
- var headings = $ ( 'h2, h3' ) . map ( function ( i , el ) {
26
- return {
27
- top : $ ( el ) . offset ( ) . top - 200 ,
28
- id : el . id
29
- }
30
- } ) ;
31
-
32
- function closest ( ) {
33
- var h ;
34
- var top = $ ( window ) . scrollTop ( ) ;
35
- var i = headings . length ;
36
- while ( i -- ) {
37
- h = headings [ i ] ;
38
- if ( top >= h . top ) return h ;
25
+ // add/remove class 'scroll' on scroll by 5px
26
+ const scrollTarget = document . querySelector ( '.logo-container' ) ;
27
+ const scrollObserver = new IntersectionObserver (
28
+ ( [ entry ] ) => {
29
+ if ( ! entry . isIntersecting ) {
30
+ document . body . classList . add ( 'scroll' ) ;
31
+ } else {
32
+ document . body . classList . remove ( 'scroll' ) ;
39
33
}
34
+ } ,
35
+ {
36
+ root : null ,
37
+ threshold : 0 ,
38
+ rootMargin : '0px 0px 0px 0px'
40
39
}
41
-
42
- var currentApiPrefix ;
43
- var parentMenuSelector ;
44
- var lastApiPrefix ;
45
-
46
- if ( document . readyState !== 'loading' ) {
47
- const languageElement = document . getElementById ( 'languageData' ) ;
48
- const languagesData = languageElement ? JSON . parse ( languageElement . dataset . languages ) : [ ] ;
49
-
50
- const langDisplay = document . getElementById ( 'current-lang' ) ;
51
-
52
- if ( langDisplay ) {
53
- const currentLanguage = window . location . pathname . split ( '/' ) [ 1 ] ;
54
- const matchedLang = languagesData . find ( lang => lang . code === currentLanguage ) ;
55
- langDisplay . textContent = matchedLang ? matchedLang . name : 'English' ;
56
- }
57
- }
58
-
59
- $ ( document ) . scroll ( function ( ) {
60
- var h = closest ( ) ;
61
- if ( ! h ) return ;
62
-
63
- currentApiPrefix = h . id . split ( '.' ) [ 0 ] ;
64
- parentMenuSelector = '#' + currentApiPrefix + '-menu' ;
65
-
66
- $ ( parentMenuSelector ) . addClass ( 'active' ) ;
67
-
68
- if ( lastApiPrefix && ( lastApiPrefix != currentApiPrefix ) ) {
69
- $ ( '#' + lastApiPrefix + '-menu' ) . removeClass ( 'active' ) ;
40
+ ) ;
41
+
42
+ if ( scrollTarget ) scrollObserver . observe ( scrollTarget ) ;
43
+
44
+ // heighlight current Menu on scroll
45
+ const headings = Array . from ( document . querySelectorAll ( "h2, h3" ) ) ;
46
+ const menuLinks = document . querySelectorAll ( "#menu li a" ) ;
47
+
48
+ const observerOptions = {
49
+ root : null ,
50
+ rootMargin : "-10% 0px -65% 0px" ,
51
+ threshold : 1 ,
52
+ } ;
53
+
54
+ const menuObserver = new IntersectionObserver ( ( entries ) => {
55
+ entries . forEach ( ( entry ) => {
56
+ if ( entry . isIntersecting ) {
57
+ const currentApiPrefix = entry . target . id . split ( "." ) [ 0 ] ;
58
+ const parentMenuSelector = `#${ currentApiPrefix } -menu` ;
59
+ const parentMenuEl = document . querySelector ( parentMenuSelector ) ;
60
+
61
+ // open submenu on scroll
62
+ if ( parentMenuEl ) parentMenuEl . classList . add ( "active" ) ;
63
+
64
+ // Remove active class from last menu item
65
+ const lastActiveMenu = document . querySelector ( ".active[id$='-menu']" ) ;
66
+ if ( lastActiveMenu && lastActiveMenu . id !== parentMenuEl . id ) {
67
+ lastActiveMenu . classList . remove ( "active" ) ;
68
+ }
69
+
70
+ // Update active link
71
+ menuLinks . forEach ( ( link ) => link . classList . remove ( "active" ) ) ;
72
+ const activeLink = document . querySelector ( `a[href="#${ entry . target . id } "]` ) ;
73
+ if ( activeLink && ! activeLink . classList . contains ( "active" ) ) activeLink . classList . add ( "active" ) ;
70
74
}
71
-
72
- $ ( '#menu li a' ) . removeClass ( 'active' ) ;
73
-
74
- var a = $ ( 'a[href="#' + h . id + '"]' ) ;
75
- a . addClass ( 'active' ) ;
76
-
77
- lastApiPrefix = currentApiPrefix . split ( '.' ) [ 0 ] ;
78
- } )
79
-
80
- // i18n notice
81
- if ( readCookie ( 'i18nClose' ) ) {
82
- $ ( '#i18n-notice-box' ) . hide ( ) ;
83
- $ ( "#i18n-notice-box" ) . addClass ( "hidden" ) ;
84
- }
85
- else {
86
- $ ( '#close-i18n-notice-box' ) . on ( 'click' , function ( ) {
87
- $ ( '#i18n-notice-box' ) . hide ( ) ;
88
- $ ( "#i18n-notice-box" ) . addClass ( "hidden" ) ;
75
+ } ) ;
76
+ } , observerOptions ) ;
77
+
78
+ headings . forEach ( ( heading ) => menuObserver . observe ( heading ) ) ;
79
+
80
+ // i18n message box : this box appears hidden for all page.lang != 'en'
81
+ const isI18nCookie = readCookie ( 'i18nClose' ) ;
82
+ if ( i18nMsgBox && ! isI18nCookie ) {
83
+ const closeI18nBtn = document . getElementById ( "close-i18n-notice-box" ) ;
84
+ // show notice box
85
+ i18nMsgBox . hidden = false ;
86
+ // close notice box
87
+ if ( closeI18nBtn ) {
88
+ closeI18nBtn . addEventListener ( "click" , ( ) => {
89
+ // hide notice
90
+ i18nMsgBox . hidden = true ;
91
+ // set session cookie
89
92
createCookie ( 'i18nClose' , 1 ) ;
90
- } )
93
+ } ) ;
94
+
95
+ // keyboard a11y
96
+ closeI18nBtn . addEventListener ( "keydown" , ( e ) => {
97
+ if ( e . key === "Enter" || e . key === " " ) {
98
+ e . preventDefault ( ) ;
99
+ closeI18nBtn . click ( ) ;
100
+ }
101
+ } ) ;
91
102
}
92
- } )
93
-
94
-
103
+ } ;
95
104
96
105
function createCookie ( name , value , days ) {
97
- var expires ;
98
-
106
+ let expires = "" ;
99
107
if ( days ) {
100
- var date = new Date ( ) ;
101
- date . setTime ( date . getTime ( ) + ( days * 24 * 60 * 60 * 1000 ) ) ;
102
- expires = "; expires=" + date . toGMTString ( ) ;
103
- } else {
104
- expires = "" ;
108
+ const date = new Date ( ) ;
109
+ date . setTime ( date . getTime ( ) + ( days * 864e5 ) ) ;
110
+ expires = "; expires=" + date . toUTCString ( ) ;
105
111
}
106
- document . cookie = encodeURIComponent ( name ) + "=" + encodeURIComponent ( value ) + expires + " ; path=/" ;
112
+ document . cookie = ` ${ encodeURIComponent ( name ) } = ${ encodeURIComponent ( value ) } ${ expires } ; path=/; SameSite=Lax; Secure` ;
107
113
}
108
114
109
115
function readCookie ( name ) {
110
- var nameEQ = encodeURIComponent ( name ) + "=" ;
111
- var ca = document . cookie . split ( ';' ) ;
112
- for ( var i = 0 ; i < ca . length ; i ++ ) {
113
- var c = ca [ i ] ;
116
+ const nameEQ = encodeURIComponent ( name ) + "=" ;
117
+ const ca = document . cookie . split ( ';' ) ;
118
+ for ( let i = 0 ; i < ca . length ; i ++ ) {
119
+ let c = ca [ i ] ;
114
120
while ( c . charAt ( 0 ) === ' ' ) c = c . substring ( 1 , c . length ) ;
115
121
if ( c . indexOf ( nameEQ ) === 0 ) return decodeURIComponent ( c . substring ( nameEQ . length , c . length ) ) ;
116
122
}
117
123
return null ;
118
124
}
119
-
120
- function eraseCookie ( name ) {
121
- createCookie ( name , "" , - 1 ) ;
122
- }
0 commit comments