rebuilding site Wed May 18 09:11:42 AM CST 2022
[uweb.git] / js / index.js
blob776bbb95f6be2fa1f6e00d8eac7f0b490eb92d9b
1 /**
2  * Created by Xiaotao.Nie on 09/04/2018.
3  * All right reserved
4  * IF you have any question please email onlythen@yeah.net
5  */
7 // Global functions and listeners
8 window.onresize = () => {
9     // when window resize , we show remove some class that me be added
10     // often for debug
11     if(window.document.documentElement.clientWidth > 680){
12         let aboutContent = document.getElementById('nav-content')
13         aboutContent.classList.remove('hide-block')
14         aboutContent.classList.remove('show-block');
15     }
16     // if(window.isPost){
17         // reLayout()
18     // }
20     reHeightToc();
23 // Nav switch function on mobile
24 /*****************************************************************************/
25 const navToggle = document.getElementById('site-nav-toggle');
26 navToggle.addEventListener('click', () => {
27     let aboutContent = document.getElementById('nav-content')
28     if (!aboutContent.classList.contains('show-block')) {
29         aboutContent.classList.add('show-block');
30         aboutContent.classList.remove('hide-block')
31     } else {
32         aboutContent.classList.add('hide-block')
33         aboutContent.classList.remove('show-block');
34     }
38 // global search
39 /*****************************************************************************/
41 const searchButton = document.getElementById('search')
42 const searchField = document.getElementById('search-field')
43 const searchInput = document.getElementById('search-input')
44 const searchResultContainer = document.getElementById('search-result-container')
45 const escSearch = document.getElementById('esc-search')
46 const beginSearch = document.getElementById('begin-search')
48 searchField.addEventListener('mousewheel',(e) => {
49     // e.preventDefault()
50     e.stopPropagation()
51     return false
52 }, false)
54 var searchJson;
55 var caseSensitive = false
57 searchButton.addEventListener('click', () => {
58     search()
59 });
61 escSearch.addEventListener('click',() => {
62     hideSearchField()
65 beginSearch.addEventListener('click',() => {
66     let keyword = searchInput.value;
67     if(keyword){
68         searchFromKeyWord(keyword)
69     }
72 function toggleSeachField(){
73     if (!searchField.classList.contains('show-flex-fade')) {
74         showSearchField()
75     } else {
76         hideSearchField()
77     }
80 function showSearchField() {
81     searchInput.focus()
82     searchField.classList.add('show-flex-fade');
83     searchField.classList.remove('hide-flex-fade');
86 function hideSearchField(){
87     window.onkeydown = null;
88     searchField.classList.add('hide-flex-fade');
89     searchField.classList.remove('show-flex-fade');
92 function searchFromKeyWord(keyword = ""){
93     let result = [];
95     let sildeWindowSize = 100;
97     let handleKeyword = keyword
99     if(!caseSensitive){
100         handleKeyword = keyword.toLowerCase()
101     }
102     if(!searchJson) return -1;
103     else {
104         searchJson.forEach((item) => {
106             if(!item.title || !item.content) return 0; // break
108             let title = item.title
109             let content = item.content.trim().replace(/<[^>]+>/g,"").replace(/[`#\n]/g,"");
111             let lowerTitle = title,lowerContent = content;
113             if(!caseSensitive){
114                 lowerTitle = title.toLowerCase();
115                 lowerContent = content.toLowerCase();
116             }
119             if(lowerTitle.indexOf(handleKeyword) !== -1 || lowerContent.indexOf(handleKeyword) !== -1){
120                 let resultItem = {}
121                 resultItem.title = title.replace(keyword, "<span class='red'>" + keyword + '</span>');
122                 resultItem.url = item.url;
124                 resultItem.content = [];
126                 let lastend = 0
128                 while(lowerContent.indexOf(handleKeyword) !== -1){
129                     let begin = lowerContent.indexOf(handleKeyword) - sildeWindowSize / 2 < 0 ? 0 : lowerContent.indexOf(handleKeyword) - sildeWindowSize / 2
130                     let end = begin + sildeWindowSize;
131                     let reg = caseSensitive ?  new RegExp('('+keyword+')','g') :  new RegExp('('+keyword+')','ig')
132                     resultItem.content.push("..." + content.slice(lastend + begin, lastend + end).replace(reg, "<span class='red'>$1</span>") + "...")
133                     lowerContent = lowerContent.slice(end, lowerContent.length)
134                     lastend = end
135                 }
136                 // resultItem.title = title.replace(keyword, "<span class='red'>" + keyword + '</span>');
137                 result.push(resultItem)
138             }
139         })
140     }
142     if(!result.length){
143         searchResultContainer.innerHTML = `
144             <div class="no-search-result">No Result</div>
145         `
146         return;
147     }
149     let searchFragment = document.createElement('ul')
151     for(let item of result){
152         let searchItem = document.createElement('li');
153         let searchTitle = document.createElement('a');
154         searchTitle.href = item.url
155         searchTitle.innerHTML = item.title;
156         searchItem.appendChild(searchTitle)
157         if(item.content.length) {
158             let searchContentLiContainer = document.createElement('ul')
159             for (let citem of item.content) {
160                 let searchContentFragment = document.createElement('li')
161                 searchContentFragment.innerHTML = citem;
162                 searchContentLiContainer.appendChild(searchContentFragment)
163             }
164             searchItem.appendChild(searchContentLiContainer)
165         }
166         searchFragment.appendChild(searchItem)
167     }
168     while(searchResultContainer.firstChild){
169         searchResultContainer.removeChild(searchResultContainer.firstChild)
170     }
171     searchResultContainer.appendChild(searchFragment)
174 function search(){
176     toggleSeachField()
178     window.onkeydown = (e) => {
179         if (e.which === 27) {
180             /** 这里编写当ESC按下时的处理逻辑! */
181             toggleSeachField()
182         } else if(e.which === 13){
183             // 回车按下
184             let keyword = searchInput.value;
185             if(keyword){
186                 searchFromKeyWord(keyword)
187             }
188         }
189     }
192     if(!searchJson){
193         let isXml;
194         let search_path = window.hexo_search_path;
195         if (search_path.length === 0) {
196             search_path = "search.json";
197         } else if (/json$/i.test(search_path)) {
198             isXml = false;
199         }
200         let path = window.hexo_root+ search_path;
201         $.ajax({
202             url: path,
203             dataType: isXml ? "xml" : "json",
204             async: true,
205             success: function (res) {
206                 searchJson = isXml ? $("entry", res).map(function() {
207                     return {
208                         title: $("title", this).text(),
209                         content: $("content",this).text(),
210                         url: $("url" , this).text()
211                     };
212                 }).get() : res;
213             }
214         });
215     }
219 // directory function in post pages
220 /*****************************************************************************/
221 function getDistanceOfLeft(obj) {
222     let left = 0;
223     let top = 0;
224     while (obj) {
225         left += obj.offsetLeft;
226         top += obj.offsetTop;
227         obj = obj.offsetParent;
228     }
229     return {
230         left:left,
231         top:top
232     };
235 var toc = document.getElementById('toc')
237 var tocToTop = getDistanceOfLeft(toc).top;
239 function reHeightToc(){
240     if(toc) { // resize toc height
241         toc.style.height = ( document.documentElement.clientHeight - 10 ) + 'px';
242         toc.style.overflowY = 'scroll';
243     }
246 reHeightToc();
248 if(window.isPost){
249     var result = []
251     var nameSet = new Set();
253     if(!toc || !toc.children || !toc.children[0]){
254         // do nothing
255     }
256     else {
257         if (toc.children[0].nodeName === "OL") {
258             let ol = Array.from(toc.children[0].children)
260             function getArrayFromOl(ol) {
261                 let result = []
263                 // let escape = function (item) {
264                 //     return item.replace(/<[^>]+>/g, "").replace(/^\s\s*/, '').replace(/\s\s*$/, '').replace(/[\. _]/g, '-')
265                 // }
267                 ol.forEach((item) => {
268                     if (item.children.length === 1) {
269                         // TODO: need change
270                         let value = item.children[0].getAttribute('href').replace(/^#/,"")
271                         result.push({
272                             value: [value],
273                             dom: item
274                         })
275                         nameSet.add(value)
276                     }
277                     else {
278                         let concatArray = getArrayFromOl(Array.from(item.children[1].children))
279                         nameSet.add(item.children[0].getAttribute('href').replace(/^#/,""))
280                         result.push({
281                             value: [item.children[0].getAttribute('href').replace(/^#/,"")].concat(concatArray.reduce((p, n) => {
282                                 p = p.concat(n.value)
283                                 return p;
284                             }, [])),
285                             dom: item
286                         })
287                         result = result.concat(concatArray)
288                     }
289                 })
290                 return result
291             }
293             result = getArrayFromOl(ol)
294         }
296         var nameArray = Array.from(nameSet)
298         function reLayout() {
299             let scrollToTop = document.documentElement.scrollTop || window.pageYOffset // Safari is special
300             if(tocToTop === 0) {
301                 // Fix bug that when resize window the toc layout may be wrong
302                 toc = document.getElementById('toc')
303                 toc.classList.remove('toc-fixed')
304                 tocToTop = getDistanceOfLeft(toc).top;
305             }
306             if (tocToTop <= scrollToTop + 10) {
307                 if (!toc.classList.contains('toc-fixed'))
308                     toc.classList.add('toc-fixed')
309             } else {
310                 if (toc.classList.contains('toc-fixed'))
311                     toc.classList.remove('toc-fixed')
312             }
314             let minTop = 9999;
315             let minTopsValue = ""
317             for (let item of nameArray) {
318                 let dom = document.getElementById(item) || document.getElementById(item.replace(/\s/g, ''))
319                 if (!dom) continue
320                 let toTop = getDistanceOfLeft(dom).top - scrollToTop;
322                 if (Math.abs(toTop) < minTop) {
323                     minTop = Math.abs(toTop)
324                     minTopsValue = item
325                 }
327                 // console.log(minTopsValue, minTop)
328             }
330             if (minTopsValue) {
331                 for (let item of result) {
332                     if (item.value.indexOf(minTopsValue) !== -1) {
333                         item.dom.classList.add("active")
334                     } else {
335                         item.dom.classList.remove("active")
336                     }
337                 }
338             }
339         }
341         reLayout()
343         window.addEventListener('scroll', (e) => {
344             reLayout()
345         })
346     }