|
231 | 231 |
|
232 | 232 |
|
233 | 233 | <li class="menu-item menu-item-commonweal"> |
234 | | - <a href="/404.html" rel="section"> |
| 234 | + <a href="/404/" rel="section"> |
235 | 235 |
|
236 | | - <i class="menu-item-icon fa fa-fw fa-question-circle"></i> <br> |
| 236 | + <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br> |
237 | 237 |
|
238 | 238 | 公益404 |
239 | 239 | </a> |
|
251 | 251 |
|
252 | 252 |
|
253 | 253 |
|
| 254 | + <li class="menu-item menu-item-search"> |
| 255 | + |
| 256 | + <a href="javascript:;" class="popup-trigger"> |
| 257 | + |
| 258 | + |
| 259 | + <i class="menu-item-icon fa fa-search fa-fw"></i> <br> |
| 260 | + |
| 261 | + 搜索 |
| 262 | + </a> |
| 263 | + </li> |
| 264 | + |
254 | 265 | </ul> |
255 | 266 |
|
256 | 267 |
|
257 | 268 |
|
| 269 | + <div class="site-search"> |
| 270 | + |
| 271 | + <div class="popup search-popup local-search-popup"> |
| 272 | + <div class="local-search-header clearfix"> |
| 273 | + <span class="search-icon"> |
| 274 | + <i class="fa fa-search"></i> |
| 275 | + </span> |
| 276 | + <span class="popup-btn-close"> |
| 277 | + <i class="fa fa-times-circle"></i> |
| 278 | + </span> |
| 279 | + <div class="local-search-input-wrapper"> |
| 280 | + <input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input"> |
| 281 | + </div> |
| 282 | + </div> |
| 283 | + <div id="local-search-result"></div> |
| 284 | +</div> |
| 285 | + |
| 286 | + |
| 287 | + |
| 288 | + </div> |
| 289 | + |
258 | 290 | </nav> |
259 | 291 |
|
260 | 292 |
|
@@ -709,6 +741,323 @@ <h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerl |
709 | 741 |
|
710 | 742 |
|
711 | 743 |
|
| 744 | + |
| 745 | + <script type="text/javascript"> |
| 746 | + // Popup Window; |
| 747 | + var isfetched = false; |
| 748 | + var isXml = true; |
| 749 | + // Search DB path; |
| 750 | + var search_path = "search.xml"; |
| 751 | + if (search_path.length === 0) { |
| 752 | + search_path = "search.xml"; |
| 753 | + } else if (/json$/i.test(search_path)) { |
| 754 | + isXml = false; |
| 755 | + } |
| 756 | + var path = "/" + search_path; |
| 757 | + // monitor main search box; |
| 758 | + |
| 759 | + var onPopupClose = function (e) { |
| 760 | + $('.popup').hide(); |
| 761 | + $('#local-search-input').val(''); |
| 762 | + $('.search-result-list').remove(); |
| 763 | + $('#no-result').remove(); |
| 764 | + $(".local-search-pop-overlay").remove(); |
| 765 | + $('body').css('overflow', ''); |
| 766 | + } |
| 767 | + |
| 768 | + function proceedsearch() { |
| 769 | + $("body") |
| 770 | + .append('<div class="search-popup-overlay local-search-pop-overlay"></div>') |
| 771 | + .css('overflow', 'hidden'); |
| 772 | + $('.search-popup-overlay').click(onPopupClose); |
| 773 | + $('.popup').toggle(); |
| 774 | + var $localSearchInput = $('#local-search-input'); |
| 775 | + $localSearchInput.attr("autocapitalize", "none"); |
| 776 | + $localSearchInput.attr("autocorrect", "off"); |
| 777 | + $localSearchInput.focus(); |
| 778 | + } |
| 779 | + |
| 780 | + // search function; |
| 781 | + var searchFunc = function(path, search_id, content_id) { |
| 782 | + 'use strict'; |
| 783 | + |
| 784 | + // start loading animation |
| 785 | + $("body") |
| 786 | + .append('<div class="search-popup-overlay local-search-pop-overlay">' + |
| 787 | + '<div id="search-loading-icon">' + |
| 788 | + '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' + |
| 789 | + '</div>' + |
| 790 | + '</div>') |
| 791 | + .css('overflow', 'hidden'); |
| 792 | + $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center'); |
| 793 | + |
| 794 | + $.ajax({ |
| 795 | + url: path, |
| 796 | + dataType: isXml ? "xml" : "json", |
| 797 | + async: true, |
| 798 | + success: function(res) { |
| 799 | + // get the contents from search data |
| 800 | + isfetched = true; |
| 801 | + $('.popup').detach().appendTo('.header-inner'); |
| 802 | + var datas = isXml ? $("entry", res).map(function() { |
| 803 | + return { |
| 804 | + title: $("title", this).text(), |
| 805 | + content: $("content",this).text(), |
| 806 | + url: $("url" , this).text() |
| 807 | + }; |
| 808 | + }).get() : res; |
| 809 | + var input = document.getElementById(search_id); |
| 810 | + var resultContent = document.getElementById(content_id); |
| 811 | + var inputEventFunction = function() { |
| 812 | + var searchText = input.value.trim().toLowerCase(); |
| 813 | + var keywords = searchText.split(/[\s\-]+/); |
| 814 | + if (keywords.length > 1) { |
| 815 | + keywords.push(searchText); |
| 816 | + } |
| 817 | + var resultItems = []; |
| 818 | + if (searchText.length > 0) { |
| 819 | + // perform local searching |
| 820 | + datas.forEach(function(data) { |
| 821 | + var isMatch = false; |
| 822 | + var hitCount = 0; |
| 823 | + var searchTextCount = 0; |
| 824 | + var title = data.title.trim(); |
| 825 | + var titleInLowerCase = title.toLowerCase(); |
| 826 | + var content = data.content.trim().replace(/<[^>]+>/g,""); |
| 827 | + var contentInLowerCase = content.toLowerCase(); |
| 828 | + var articleUrl = decodeURIComponent(data.url); |
| 829 | + var indexOfTitle = []; |
| 830 | + var indexOfContent = []; |
| 831 | + // only match articles with not empty titles |
| 832 | + if(title != '') { |
| 833 | + keywords.forEach(function(keyword) { |
| 834 | + function getIndexByWord(word, text, caseSensitive) { |
| 835 | + var wordLen = word.length; |
| 836 | + if (wordLen === 0) { |
| 837 | + return []; |
| 838 | + } |
| 839 | + var startPosition = 0, position = [], index = []; |
| 840 | + if (!caseSensitive) { |
| 841 | + text = text.toLowerCase(); |
| 842 | + word = word.toLowerCase(); |
| 843 | + } |
| 844 | + while ((position = text.indexOf(word, startPosition)) > -1) { |
| 845 | + index.push({position: position, word: word}); |
| 846 | + startPosition = position + wordLen; |
| 847 | + } |
| 848 | + return index; |
| 849 | + } |
| 850 | + |
| 851 | + indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false)); |
| 852 | + indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false)); |
| 853 | + }); |
| 854 | + if (indexOfTitle.length > 0 || indexOfContent.length > 0) { |
| 855 | + isMatch = true; |
| 856 | + hitCount = indexOfTitle.length + indexOfContent.length; |
| 857 | + } |
| 858 | + } |
| 859 | + |
| 860 | + // show search results |
| 861 | + |
| 862 | + if (isMatch) { |
| 863 | + // sort index by position of keyword |
| 864 | + |
| 865 | + [indexOfTitle, indexOfContent].forEach(function (index) { |
| 866 | + index.sort(function (itemLeft, itemRight) { |
| 867 | + if (itemRight.position !== itemLeft.position) { |
| 868 | + return itemRight.position - itemLeft.position; |
| 869 | + } else { |
| 870 | + return itemLeft.word.length - itemRight.word.length; |
| 871 | + } |
| 872 | + }); |
| 873 | + }); |
| 874 | + |
| 875 | + // merge hits into slices |
| 876 | + |
| 877 | + function mergeIntoSlice(text, start, end, index) { |
| 878 | + var item = index[index.length - 1]; |
| 879 | + var position = item.position; |
| 880 | + var word = item.word; |
| 881 | + var hits = []; |
| 882 | + var searchTextCountInSlice = 0; |
| 883 | + while (position + word.length <= end && index.length != 0) { |
| 884 | + if (word === searchText) { |
| 885 | + searchTextCountInSlice++; |
| 886 | + } |
| 887 | + hits.push({position: position, length: word.length}); |
| 888 | + var wordEnd = position + word.length; |
| 889 | + |
| 890 | + // move to next position of hit |
| 891 | + |
| 892 | + index.pop(); |
| 893 | + while (index.length != 0) { |
| 894 | + item = index[index.length - 1]; |
| 895 | + position = item.position; |
| 896 | + word = item.word; |
| 897 | + if (wordEnd > position) { |
| 898 | + index.pop(); |
| 899 | + } else { |
| 900 | + break; |
| 901 | + } |
| 902 | + } |
| 903 | + } |
| 904 | + searchTextCount += searchTextCountInSlice; |
| 905 | + return { |
| 906 | + hits: hits, |
| 907 | + start: start, |
| 908 | + end: end, |
| 909 | + searchTextCount: searchTextCountInSlice |
| 910 | + }; |
| 911 | + } |
| 912 | + |
| 913 | + var slicesOfTitle = []; |
| 914 | + if (indexOfTitle.length != 0) { |
| 915 | + slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle)); |
| 916 | + } |
| 917 | + |
| 918 | + var slicesOfContent = []; |
| 919 | + while (indexOfContent.length != 0) { |
| 920 | + var item = indexOfContent[indexOfContent.length - 1]; |
| 921 | + var position = item.position; |
| 922 | + var word = item.word; |
| 923 | + // cut out 100 characters |
| 924 | + var start = position - 20; |
| 925 | + var end = position + 80; |
| 926 | + if(start < 0){ |
| 927 | + start = 0; |
| 928 | + } |
| 929 | + if (end < position + word.length) { |
| 930 | + end = position + word.length; |
| 931 | + } |
| 932 | + if(end > content.length){ |
| 933 | + end = content.length; |
| 934 | + } |
| 935 | + slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent)); |
| 936 | + } |
| 937 | + |
| 938 | + // sort slices in content by search text's count and hits' count |
| 939 | + |
| 940 | + slicesOfContent.sort(function (sliceLeft, sliceRight) { |
| 941 | + if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) { |
| 942 | + return sliceRight.searchTextCount - sliceLeft.searchTextCount; |
| 943 | + } else if (sliceLeft.hits.length !== sliceRight.hits.length) { |
| 944 | + return sliceRight.hits.length - sliceLeft.hits.length; |
| 945 | + } else { |
| 946 | + return sliceLeft.start - sliceRight.start; |
| 947 | + } |
| 948 | + }); |
| 949 | + |
| 950 | + // select top N slices in content |
| 951 | + |
| 952 | + var upperBound = parseInt('1'); |
| 953 | + if (upperBound >= 0) { |
| 954 | + slicesOfContent = slicesOfContent.slice(0, upperBound); |
| 955 | + } |
| 956 | + |
| 957 | + // highlight title and content |
| 958 | + |
| 959 | + function highlightKeyword(text, slice) { |
| 960 | + var result = ''; |
| 961 | + var prevEnd = slice.start; |
| 962 | + slice.hits.forEach(function (hit) { |
| 963 | + result += text.substring(prevEnd, hit.position); |
| 964 | + var end = hit.position + hit.length; |
| 965 | + result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>'; |
| 966 | + prevEnd = end; |
| 967 | + }); |
| 968 | + result += text.substring(prevEnd, slice.end); |
| 969 | + return result; |
| 970 | + } |
| 971 | + |
| 972 | + var resultItem = ''; |
| 973 | + |
| 974 | + if (slicesOfTitle.length != 0) { |
| 975 | + resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>"; |
| 976 | + } else { |
| 977 | + resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>"; |
| 978 | + } |
| 979 | + |
| 980 | + slicesOfContent.forEach(function (slice) { |
| 981 | + resultItem += "<a href='" + articleUrl + "'>" + |
| 982 | + "<p class=\"search-result\">" + highlightKeyword(content, slice) + |
| 983 | + "...</p>" + "</a>"; |
| 984 | + }); |
| 985 | + |
| 986 | + resultItem += "</li>"; |
| 987 | + resultItems.push({ |
| 988 | + item: resultItem, |
| 989 | + searchTextCount: searchTextCount, |
| 990 | + hitCount: hitCount, |
| 991 | + id: resultItems.length |
| 992 | + }); |
| 993 | + } |
| 994 | + }) |
| 995 | + }; |
| 996 | + if (keywords.length === 1 && keywords[0] === "") { |
| 997 | + resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>' |
| 998 | + } else if (resultItems.length === 0) { |
| 999 | + resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>' |
| 1000 | + } else { |
| 1001 | + resultItems.sort(function (resultLeft, resultRight) { |
| 1002 | + if (resultLeft.searchTextCount !== resultRight.searchTextCount) { |
| 1003 | + return resultRight.searchTextCount - resultLeft.searchTextCount; |
| 1004 | + } else if (resultLeft.hitCount !== resultRight.hitCount) { |
| 1005 | + return resultRight.hitCount - resultLeft.hitCount; |
| 1006 | + } else { |
| 1007 | + return resultRight.id - resultLeft.id; |
| 1008 | + } |
| 1009 | + }); |
| 1010 | + var searchResultList = '<ul class=\"search-result-list\">'; |
| 1011 | + resultItems.forEach(function (result) { |
| 1012 | + searchResultList += result.item; |
| 1013 | + }) |
| 1014 | + searchResultList += "</ul>"; |
| 1015 | + resultContent.innerHTML = searchResultList; |
| 1016 | + } |
| 1017 | + } |
| 1018 | + |
| 1019 | + if ('auto' === 'auto') { |
| 1020 | + input.addEventListener('input', inputEventFunction); |
| 1021 | + } else { |
| 1022 | + $('.search-icon').click(inputEventFunction); |
| 1023 | + input.addEventListener('keypress', function (event) { |
| 1024 | + if (event.keyCode === 13) { |
| 1025 | + inputEventFunction(); |
| 1026 | + } |
| 1027 | + }); |
| 1028 | + } |
| 1029 | + |
| 1030 | + // remove loading animation |
| 1031 | + $(".local-search-pop-overlay").remove(); |
| 1032 | + $('body').css('overflow', ''); |
| 1033 | + |
| 1034 | + proceedsearch(); |
| 1035 | + } |
| 1036 | + }); |
| 1037 | + } |
| 1038 | + |
| 1039 | + // handle and trigger popup window; |
| 1040 | + $('.popup-trigger').click(function(e) { |
| 1041 | + e.stopPropagation(); |
| 1042 | + if (isfetched === false) { |
| 1043 | + searchFunc(path, 'local-search-input', 'local-search-result'); |
| 1044 | + } else { |
| 1045 | + proceedsearch(); |
| 1046 | + }; |
| 1047 | + }); |
| 1048 | + |
| 1049 | + $('.popup-btn-close').click(onPopupClose); |
| 1050 | + $('.popup').click(function(e){ |
| 1051 | + e.stopPropagation(); |
| 1052 | + }); |
| 1053 | + $(document).on('keyup', function (event) { |
| 1054 | + var shouldDismissSearchPopup = event.which === 27 && |
| 1055 | + $('.search-popup').is(':visible'); |
| 1056 | + if (shouldDismissSearchPopup) { |
| 1057 | + onPopupClose(); |
| 1058 | + } |
| 1059 | + }); |
| 1060 | + </script> |
712 | 1061 |
|
713 | 1062 |
|
714 | 1063 |
|
|
0 commit comments