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+ }
913
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+ } )
2122 } )
23+ }
2224
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' ) ;
3933 }
34+ } ,
35+ {
36+ root : null ,
37+ threshold : 0 ,
38+ rootMargin : '0px 0px 0px 0px'
4039 }
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" ) ;
7074 }
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
8992 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+ } ) ;
91102 }
92- } )
93-
94-
103+ } ;
95104
96105function createCookie ( name , value , days ) {
97- var expires ;
98-
106+ let expires = "" ;
99107 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 ( ) ;
105111 }
106- document . cookie = encodeURIComponent ( name ) + "=" + encodeURIComponent ( value ) + expires + " ; path=/" ;
112+ document . cookie = ` ${ encodeURIComponent ( name ) } = ${ encodeURIComponent ( value ) } ${ expires } ; path=/; SameSite=Lax; Secure` ;
107113}
108114
109115function 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 ] ;
114120 while ( c . charAt ( 0 ) === ' ' ) c = c . substring ( 1 , c . length ) ;
115121 if ( c . indexOf ( nameEQ ) === 0 ) return decodeURIComponent ( c . substring ( nameEQ . length , c . length ) ) ;
116122 }
117123 return null ;
118124}
119-
120- function eraseCookie ( name ) {
121- createCookie ( name , "" , - 1 ) ;
122- }
0 commit comments