1
+ /*!
2
+ * Interaction for online textbook.
3
+ * by Juan Carlos Ponce Campuzano 7/Feb/2024
4
+ * Updated: 22/Feb/2024
5
+ * License: CC BY-NC-SA 4.0 DEED
6
+ * Attribution-NonCommercial-ShareAlike 4.0 International
7
+ * https://creativecommons.org/licenses/by-nc-sa/4.0/?ref=chooser-v1
8
+ */
9
+
10
+ /*
11
+ Content:
12
+ * - Dark mode
13
+ * - Modal
14
+ * - Include HTML
15
+ * - Scroll up to "id" tags for hyperlinks
16
+ * - To top button
17
+ * - Navigation bar interaction
18
+ */
19
+
20
+ /*---------------------------------------------------------------*/
21
+ /* Dark mode function */
22
+ const darkModeToggle = document . getElementById ( 'dark-mode-toggle' )
23
+ darkModeToggle . addEventListener ( 'click' , ( ) => {
24
+ document . body . classList . toggle ( 'latex-dark' ) ;
25
+ } ) ;
26
+
27
+ /*
28
+ let darkModeIcon = document.getElementById("dark-mode-toggle");
29
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
30
+ document.body.classList.add('latex-dark');
31
+ darkModeIcon.innerHTML = '<i class="fa-solid fa-moon"></i>';
32
+ } else {
33
+ darkModeIcon.innerHTML = '<i class="fa-regular fa-sun"></i>';
34
+ }*/
35
+
36
+ // Function to replace text for Dark mode
37
+ function toggleMode ( ) {
38
+ // Get the element containing the text
39
+ var element = document . getElementById ( "dark-mode-toggle" ) ;
40
+
41
+ // Toggle between "text01" and "text02"
42
+ if ( element . innerHTML . trim ( ) === '<i class="fa-solid fa-moon"></i>' ) {
43
+ element . innerHTML = '<i class="fa-regular fa-sun"></i>' ;
44
+ localStorage . setItem ( 'mode' , 'light' ) ;
45
+ } else {
46
+ element . innerHTML = '<i class="fa-solid fa-moon"></i>' ;
47
+ localStorage . setItem ( 'mode' , 'dark' ) ;
48
+ }
49
+ }
50
+
51
+ // Function to load mode from local storage
52
+ function loadMode ( ) {
53
+ var element = document . getElementById ( "dark-mode-toggle" ) ;
54
+ var mode = localStorage . getItem ( 'mode' ) ;
55
+
56
+ if ( mode === 'light' ) {
57
+ element . innerHTML = '<i class="fa-regular fa-sun"></i>' ;
58
+ } else if ( mode == 'dark' ) {
59
+ element . innerHTML = '<i class="fa-solid fa-moon"></i>' ;
60
+ document . body . classList . add ( 'latex-dark' ) ;
61
+ } else {
62
+ if ( window . matchMedia && window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ) {
63
+ document . body . classList . add ( 'latex-dark' ) ;
64
+ element . innerHTML = '<i class="fa-solid fa-moon"></i>' ;
65
+ } else {
66
+ element . innerHTML = '<i class="fa-regular fa-sun"></i>' ;
67
+ }
68
+ }
69
+ }
70
+
71
+ // Add event listener for mouse click
72
+ document . getElementById ( "dark-mode-toggle" ) . addEventListener ( "click" , toggleMode ) ;
73
+
74
+ // Load the mode when the page loads
75
+ window . onload = loadMode ;
76
+
77
+ /*---------------------------------------------------------------*/
78
+
79
+
80
+ /*---------------------------------------------------------------*/
81
+ /* The following is to scroll up to the "id" tag for hyperlinks */
82
+ // Function to handle smooth scrolling with offset
83
+
84
+ function scrollToElementWithOffset ( selector , offset ) {
85
+ var target = document . querySelector ( selector ) ;
86
+ if ( target ) {
87
+ var targetPosition = target . getBoundingClientRect ( ) . top + window . scrollY - offset ; // pageYOffset is deprecated :(
88
+ window . scrollTo ( {
89
+ top : targetPosition ,
90
+ behavior : 'smooth'
91
+ } ) ;
92
+ }
93
+ }
94
+
95
+ // Adding event listeners to all links with the class 'scroll-link'
96
+ var links = document . querySelectorAll ( 'a[href^="#"]' ) ;
97
+ links . forEach ( function ( link ) {
98
+ link . addEventListener ( 'click' , function ( event ) {
99
+ event . preventDefault ( ) ;
100
+ var targetId = this . getAttribute ( 'href' ) ;
101
+ scrollToElementWithOffset ( targetId , 50 ) ; // 50px offset, I want it below the navbar
102
+ } ) ;
103
+ } ) ;
104
+
105
+ /*---------------------------------------------------------------*/
106
+
107
+
108
+ /*---------------------------------------------------------------*/
109
+ /* Button to the top */
110
+ // Get the button
111
+
112
+ let mybutton = document . getElementById ( "toTop" ) ;
113
+ //let prevScrollpos = window.scrollY;
114
+
115
+ window . onscroll = function ( ) { scrollFunction ( ) } ;
116
+
117
+ // When the user scrolls down 500px from the top of the document, show the button
118
+ function scrollFunction ( ) {
119
+ //let currentScrollPos = window.scrollY;
120
+ //if (prevScrollpos > currentScrollPos) {
121
+ mybutton . style . display = "none" ;
122
+ //} else {
123
+ if ( document . body . scrollTop > 500 || document . documentElement . scrollTop > 500 ) {
124
+ mybutton . style . display = "block" ;
125
+ }
126
+ //}
127
+ //prevScrollpos = currentScrollPos;
128
+ }
129
+
130
+ // When the user clicks on the button, scroll to the top of the document
131
+ function topFunction ( ) {
132
+ let tocLinks = document . querySelectorAll ( '.toc-chapter a' ) ;
133
+ tocLinks . forEach ( ( link ) => {
134
+ //link.classList.remove('active');
135
+ link . classList . remove ( 'highlight' ) ;
136
+ } ) ;
137
+ document . body . scrollTop = 0 ;
138
+ document . documentElement . scrollTop = 0 ;
139
+ }
140
+
141
+ /*---------------------------------------------------------------*/
142
+
143
+
144
+ /*---------------------------------------------------------------*/
145
+ /* Interaction with the fixed navbar on the top */
146
+ /* left-link right-link */
147
+ const leftLink = document . getElementById ( 'prev-link' ) ;
148
+ const rightLink = document . getElementById ( 'next-link' ) ;
149
+ const centerLink = document . getElementById ( 'center-link' ) ;
150
+
151
+ // Function to handle hover events for links
152
+ function handleLinkHover ( event , originalSelector , hoverSelector ) {
153
+ // Find the original and hover content elements
154
+ const contentOriginal = centerLink . querySelector ( originalSelector ) ;
155
+ const contentHover = centerLink . querySelector ( hoverSelector ) ;
156
+
157
+ // Check if the content elements exist before manipulating them
158
+ if ( contentOriginal && contentHover ) {
159
+ // Toggle display based on event type
160
+ if ( event . type === 'mouseenter' ) {
161
+ contentOriginal . style . display = 'none' ;
162
+ contentHover . style . display = 'inline' ;
163
+ } else if ( event . type === 'mouseleave' ) {
164
+ contentOriginal . style . display = 'inline' ;
165
+ contentHover . style . display = 'none' ;
166
+ }
167
+ }
168
+ }
169
+
170
+ // Add event listeners only if the elements exist
171
+ if ( leftLink ) {
172
+ leftLink . addEventListener ( 'mouseenter' , ( event ) => {
173
+ handleLinkHover ( event , '.content-original' , '.content-hover-previous' ) ;
174
+ } ) ;
175
+
176
+ leftLink . addEventListener ( 'mouseleave' , ( event ) => {
177
+ handleLinkHover ( event , '.content-original' , '.content-hover-previous' ) ;
178
+ } ) ;
179
+ }
180
+
181
+ if ( rightLink ) {
182
+ rightLink . addEventListener ( 'mouseenter' , ( event ) => {
183
+ handleLinkHover ( event , '.content-original' , '.content-hover-next' ) ;
184
+ } ) ;
185
+
186
+ rightLink . addEventListener ( 'mouseleave' , ( event ) => {
187
+ handleLinkHover ( event , '.content-original' , '.content-hover-next' ) ;
188
+ } ) ;
189
+ }
190
+
191
+ if ( centerLink ) {
192
+ centerLink . addEventListener ( 'mouseenter' , ( event ) => {
193
+ // When hovering on center link, show general hover content
194
+ handleLinkHover ( event , '.content-original' , '.content-hover' ) ;
195
+ } ) ;
196
+
197
+ centerLink . addEventListener ( 'mouseleave' , ( event ) => {
198
+ // When leaving center link, show original content
199
+ handleLinkHover ( event , '.content-original' , '.content-hover' ) ;
200
+ } ) ;
201
+ }
202
+
203
+ /*---------------------------------------------------------------*/
204
+
205
+
206
+ /*---------------------------------------------------------------*/
207
+ // Toc for each chapter
208
+
209
+ window . addEventListener ( 'scroll' , function ( ) {
210
+ let sections = document . querySelectorAll ( 'div[id^="section"]' ) ;
211
+ let tocLinks = document . querySelectorAll ( '.toc-chapter a' ) ;
212
+ let scrollPosition = window . scrollY ;
213
+
214
+ sections . forEach ( ( section , index ) => {
215
+ let sectionTop = section . offsetTop - 100 ; // Adjust as needed
216
+ let sectionBottom = sectionTop + section . clientHeight ;
217
+
218
+ if ( scrollPosition >= sectionTop && scrollPosition < sectionBottom ) {
219
+ tocLinks . forEach ( ( link ) => {
220
+ //link.classList.remove('active');
221
+ link . classList . remove ( 'highlight' ) ;
222
+ } ) ;
223
+ //tocLinks[index].classList.add('active');
224
+ tocLinks [ index ] . classList . add ( 'highlight' ) ;
225
+ }
226
+ } ) ;
227
+ } ) ;
228
+
229
+ /*---------------------------------------------------------------*/
230
+
231
+
232
+ /*---------------------------------------------------------------*/
233
+ /*
234
+ I need the following code to show
235
+ modal for the "support message"
236
+ */
237
+ // Get the modal
238
+ let modal = document . getElementById ( "myModal" ) ;
239
+
240
+ // Get the <span> element that closes the modal
241
+ let span = document . getElementsByClassName ( "close" ) [ 0 ] ;
242
+
243
+ // When the user clicks the button, open the modal
244
+ //btn.onclick = function() {
245
+ // modal.style.display = "block";
246
+ //}
247
+
248
+ function showMessage ( ) {
249
+ modal . style . display = "block" ;
250
+ }
251
+
252
+ // When the user clicks on <span> (x), close the modal
253
+ span . onclick = function ( ) {
254
+ modal . style . display = "none" ;
255
+ clearInterval ( myInterval ) ;
256
+ }
257
+
258
+ // When the user clicks anywhere outside of the modal, close it
259
+ window . onclick = function ( event ) {
260
+ if ( event . target == modal ) {
261
+ modal . style . display = "none" ;
262
+ clearInterval ( myInterval ) ;
263
+ }
264
+
265
+ }
266
+
267
+ let myInterval = setInterval ( function ( ) {
268
+ showMessage ( ) ;
269
+ } , 60000 ) ;
270
+ // 3000 3 seconds
271
+ // 8000 8 seconds
272
+ // 30000 30 seconds
273
+ // 60000 1 min
274
+ // 120000 2 min
275
+ // 300000 5 mins
276
+ // 600000 10 mins
277
+ // 1200000 20 mins
278
+ // 1800000 30 mins
279
+
280
+ /*---------------------------------------------------------------*/
281
+
282
+
283
+ /*--------------- Stop scrolling on iframes ---------------------*/
284
+ var iframeContainers = document . querySelectorAll ( '.iframeContainer' ) ;
285
+
286
+ // Add event listeners for mouse entering and leaving each iframe
287
+ iframeContainers . forEach ( function ( container ) {
288
+ container . addEventListener ( 'mouseenter' , function ( ) {
289
+ // Hide overflow of the body when mouse enters iframe area
290
+ document . body . style . overflow = 'hidden' ;
291
+ } ) ;
292
+
293
+ container . addEventListener ( 'mouseleave' , function ( ) {
294
+ // Show overflow of the body when mouse leaves iframe area
295
+ document . body . style . overflow = 'auto' ;
296
+ } ) ;
297
+ } ) ;
298
+ /*---------------------------------------------------------------*/
299
+
300
+
301
+ /*---------------------------------------------------------------*/
302
+ /*
303
+ The follwing function is to include an HTML file in the slides
304
+ Source: https://www.w3schools.com/howto/howto_html_include.asp
305
+ */
306
+ function includeHTML ( ) {
307
+ let z , i , elmnt , file , xhttp ;
308
+ /*loop through a collection of all HTML elements:*/
309
+ z = document . getElementsByTagName ( "*" ) ;
310
+ for ( i = 0 ; i < z . length ; i ++ ) {
311
+ elmnt = z [ i ] ;
312
+ /*search for elements with a certain atrribute:*/
313
+ file = elmnt . getAttribute ( "w3-include-html" ) ;
314
+ if ( file ) {
315
+ /*make an HTTP request using the attribute value as the file name:*/
316
+ xhttp = new XMLHttpRequest ( ) ;
317
+ xhttp . onreadystatechange = function ( ) {
318
+ if ( this . readyState == 4 ) {
319
+ if ( this . status == 200 ) {
320
+ elmnt . innerHTML = this . responseText ;
321
+ }
322
+ if ( this . status == 404 ) {
323
+ elmnt . innerHTML = "Page not found." ;
324
+ }
325
+ /*remove the attribute, and call this function once more:*/
326
+ elmnt . removeAttribute ( "w3-include-html" ) ;
327
+ includeHTML ( ) ;
328
+ }
329
+ }
330
+ xhttp . open ( "GET" , file , true ) ;
331
+ xhttp . send ( ) ;
332
+ /*exit the function:*/
333
+ return ;
334
+ }
335
+ }
336
+ } ;
337
+
338
+ // Finally call this funciton to include HTML
339
+ includeHTML ( ) ;
340
+
341
+ /*---------------------------------------------------------------*/
0 commit comments