13
13
14
14
15
15
16
+
17
+
18
+
16
19
< meta http-equiv ="Cache-Control " content ="no-transform " />
17
20
< meta http-equiv ="Cache-Control " content ="no-siteapp " />
18
21
134
137
135
138
136
139
137
- < title > Jwt 介绍 | 谢晖的博客 </ title >
140
+ < title > Jwt 介绍 | 谢晖的博客</ title >
138
141
</ head >
139
142
140
143
< body itemscope itemtype ="http://schema.org/WebPage " lang ="zh-Hans ">
@@ -424,7 +427,6 @@ <h2 class="post-title" itemprop="name headline">
424
427
</ header >
425
428
426
429
427
-
428
430
< div class ="post-body " itemprop ="articleBody ">
429
431
430
432
@@ -798,6 +800,10 @@ <h1 id="为什么要使用JWT?"><a href="#为什么要使用JWT?" class="hea
798
800
799
801
800
802
803
+
804
+
805
+
806
+
801
807
802
808
803
809
@@ -887,10 +893,6 @@ <h1 id="为什么要使用JWT?"><a href="#为什么要使用JWT?" class="hea
887
893
888
894
889
895
890
-
891
-
892
-
893
-
894
896
895
897
896
898
@@ -904,18 +906,30 @@ <h1 id="为什么要使用JWT?"><a href="#为什么要使用JWT?" class="hea
904
906
var isfetched = false ;
905
907
// Search DB path;
906
908
var search_path = "" ;
907
- if ( search_path . length == 0 ) {
909
+ if ( search_path . length === 0 ) {
908
910
search_path = "search.xml" ;
909
911
}
910
912
var path = "/" + search_path ;
911
913
// monitor main search box;
912
914
915
+ var onPopupClose = function ( e ) {
916
+ $ ( '.popup' ) . hide ( ) ;
917
+ $ ( '#local-search-input' ) . val ( '' ) ;
918
+ $ ( '.search-result-list' ) . remove ( ) ;
919
+ $ ( '#no-result' ) . remove ( ) ;
920
+ $ ( ".local-search-pop-overlay" ) . remove ( ) ;
921
+ $ ( 'body' ) . css ( 'overflow' , '' ) ;
922
+ }
923
+
913
924
function proceedsearch ( ) {
914
925
$ ( "body" )
915
926
. append ( '<div class="search-popup-overlay local-search-pop-overlay"></div>' )
916
927
. css ( 'overflow' , 'hidden' ) ;
928
+ $ ( '.search-popup-overlay' ) . click ( onPopupClose ) ;
917
929
$ ( '.popup' ) . toggle ( ) ;
930
+ $ ( '#local-search-input' ) . focus ( ) ;
918
931
}
932
+
919
933
// search function;
920
934
var searchFunc = function ( path , search_id , content_id ) {
921
935
'use strict' ;
@@ -934,95 +948,251 @@ <h1 id="为什么要使用JWT?"><a href="#为什么要使用JWT?" class="hea
934
948
url : $ ( "url" , this ) . text ( )
935
949
} ;
936
950
} ) . get ( ) ;
937
- var $input = document . getElementById ( search_id ) ;
938
- var $resultContent = document . getElementById ( content_id ) ;
939
- $input . addEventListener ( 'input' , function ( ) {
940
- var matchcounts = 0 ;
941
- var str = '<ul class=\"search-result-list\">' ;
942
- var keywords = this . value . trim ( ) . toLowerCase ( ) . split ( / [ \s \- ] + / ) ;
943
- $resultContent . innerHTML = "" ;
944
- if ( this . value . trim ( ) . length > 1 ) {
951
+ var input = document . getElementById ( search_id ) ;
952
+ var resultContent = document . getElementById ( content_id ) ;
953
+ var inputEventFunction = function ( ) {
954
+ var searchText = input . value . trim ( ) . toLowerCase ( ) ;
955
+ var keywords = searchText . split ( / [ \s \- ] + / ) ;
956
+ if ( keywords . length > 1 ) {
957
+ keywords . push ( searchText ) ;
958
+ }
959
+ var resultItems = [ ] ;
960
+ if ( searchText . length > 0 ) {
945
961
// perform local searching
946
962
datas . forEach ( function ( data ) {
947
963
var isMatch = false ;
948
- var content_index = [ ] ;
949
- var data_title = data . title . trim ( ) . toLowerCase ( ) ;
950
- var data_content = data . content . trim ( ) . replace ( / < [ ^ > ] + > / g, "" ) . toLowerCase ( ) ;
951
- var data_url = decodeURIComponent ( data . url ) ;
952
- var index_title = - 1 ;
953
- var index_content = - 1 ;
954
- var first_occur = - 1 ;
955
- // only match artiles with not empty titles and contents
956
- if ( data_title != '' ) {
957
- keywords . forEach ( function ( keyword , i ) {
958
- index_title = data_title . indexOf ( keyword ) ;
959
- index_content = data_content . indexOf ( keyword ) ;
960
- if ( index_title >= 0 || index_content >= 0 ) {
961
- isMatch = true ;
962
- if ( i == 0 ) {
963
- first_occur = index_content ;
964
+ var hitCount = 0 ;
965
+ var searchTextCount = 0 ;
966
+ var title = data . title . trim ( ) ;
967
+ var titleInLowerCase = title . toLowerCase ( ) ;
968
+ var content = data . content . trim ( ) . replace ( / < [ ^ > ] + > / g, "" ) ;
969
+ var contentInLowerCase = content . toLowerCase ( ) ;
970
+ var articleUrl = decodeURIComponent ( data . url ) ;
971
+ var indexOfTitle = [ ] ;
972
+ var indexOfContent = [ ] ;
973
+ // only match articles with not empty titles
974
+ if ( title != '' ) {
975
+ keywords . forEach ( function ( keyword ) {
976
+ function getIndexByWord ( word , text , caseSensitive ) {
977
+ var wordLen = word . length ;
978
+ if ( wordLen === 0 ) {
979
+ return [ ] ;
980
+ }
981
+ var startPosition = 0 , position = [ ] , index = [ ] ;
982
+ if ( ! caseSensitive ) {
983
+ text = text . toLowerCase ( ) ;
984
+ word = word . toLowerCase ( ) ;
964
985
}
986
+ while ( ( position = text . indexOf ( word , startPosition ) ) > - 1 ) {
987
+ index . push ( { position : position , word : word } ) ;
988
+ startPosition = position + wordLen ;
989
+ }
990
+ return index ;
965
991
}
966
992
993
+ indexOfTitle = indexOfTitle . concat ( getIndexByWord ( keyword , titleInLowerCase , false ) ) ;
994
+ indexOfContent = indexOfContent . concat ( getIndexByWord ( keyword , contentInLowerCase , false ) ) ;
967
995
} ) ;
996
+ if ( indexOfTitle . length > 0 || indexOfContent . length > 0 ) {
997
+ isMatch = true ;
998
+ hitCount = indexOfTitle . length + indexOfContent . length ;
999
+ }
968
1000
}
1001
+
969
1002
// show search results
1003
+
970
1004
if ( isMatch ) {
971
- matchcounts += 1 ;
972
- str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>" ;
973
- var content = data . content . trim ( ) . replace ( / < [ ^ > ] + > / g, "" ) ;
974
- if ( first_occur >= 0 ) {
1005
+ // sort index by position of keyword
1006
+
1007
+ [ indexOfTitle , indexOfContent ] . forEach ( function ( index ) {
1008
+ index . sort ( function ( itemLeft , itemRight ) {
1009
+ if ( itemRight . position !== itemLeft . position ) {
1010
+ return itemRight . position - itemLeft . position ;
1011
+ } else {
1012
+ return itemLeft . word . length - itemRight . word . length ;
1013
+ }
1014
+ } ) ;
1015
+ } ) ;
1016
+
1017
+ // merge hits into slices
1018
+
1019
+ function mergeIntoSlice ( text , start , end , index ) {
1020
+ var item = index [ index . length - 1 ] ;
1021
+ var position = item . position ;
1022
+ var word = item . word ;
1023
+ var hits = [ ] ;
1024
+ var searchTextCountInSlice = 0 ;
1025
+ while ( position + word . length <= end && index . length != 0 ) {
1026
+ if ( word === searchText ) {
1027
+ searchTextCountInSlice ++ ;
1028
+ }
1029
+ hits . push ( { position : position , length : word . length } ) ;
1030
+ var wordEnd = position + word . length ;
1031
+
1032
+ // move to next position of hit
1033
+
1034
+ index . pop ( ) ;
1035
+ while ( index . length != 0 ) {
1036
+ item = index [ index . length - 1 ] ;
1037
+ position = item . position ;
1038
+ word = item . word ;
1039
+ if ( wordEnd > position ) {
1040
+ index . pop ( ) ;
1041
+ } else {
1042
+ break ;
1043
+ }
1044
+ }
1045
+ }
1046
+ searchTextCount += searchTextCountInSlice ;
1047
+ return {
1048
+ hits : hits ,
1049
+ start : start ,
1050
+ end : end ,
1051
+ searchTextCount : searchTextCountInSlice
1052
+ } ;
1053
+ }
1054
+
1055
+ var slicesOfTitle = [ ] ;
1056
+ if ( indexOfTitle . length != 0 ) {
1057
+ slicesOfTitle . push ( mergeIntoSlice ( title , 0 , title . length , indexOfTitle ) ) ;
1058
+ }
1059
+
1060
+ var slicesOfContent = [ ] ;
1061
+ while ( indexOfContent . length != 0 ) {
1062
+ var item = indexOfContent [ indexOfContent . length - 1 ] ;
1063
+ var position = item . position ;
1064
+ var word = item . word ;
975
1065
// cut out 100 characters
976
- var start = first_occur - 20 ;
977
- var end = first_occur + 80 ;
1066
+ var start = position - 20 ;
1067
+ var end = position + 80 ;
978
1068
if ( start < 0 ) {
979
1069
start = 0 ;
980
1070
}
981
- if ( start == 0 ) {
982
- end = 50 ;
1071
+ if ( end < position + word . length ) {
1072
+ end = position + word . length ;
983
1073
}
984
1074
if ( end > content . length ) {
985
1075
end = content . length ;
986
1076
}
987
- var match_content = content . substring ( start , end ) ;
988
- // highlight all keywords
989
- keywords . forEach ( function ( keyword ) {
990
- var regS = new RegExp ( keyword , "gi" ) ;
991
- match_content = match_content . replace ( regS , "<b class=\"search-keyword\">" + keyword + "</b>" ) ;
1077
+ slicesOfContent . push ( mergeIntoSlice ( content , start , end , indexOfContent ) ) ;
1078
+ }
1079
+
1080
+ // sort slices in content by search text's count and hits' count
1081
+
1082
+ slicesOfContent . sort ( function ( sliceLeft , sliceRight ) {
1083
+ if ( sliceLeft . searchTextCount !== sliceRight . searchTextCount ) {
1084
+ return sliceRight . searchTextCount - sliceLeft . searchTextCount ;
1085
+ } else if ( sliceLeft . hits . length !== sliceRight . hits . length ) {
1086
+ return sliceRight . hits . length - sliceLeft . hits . length ;
1087
+ } else {
1088
+ return sliceLeft . start - sliceRight . start ;
1089
+ }
1090
+ } ) ;
1091
+
1092
+ // select top N slices in content
1093
+
1094
+ var upperBound = parseInt ( '' ) ;
1095
+ if ( upperBound >= 0 ) {
1096
+ slicesOfContent = slicesOfContent . slice ( 0 , upperBound ) ;
1097
+ }
1098
+
1099
+ // highlight title and content
1100
+
1101
+ function highlightKeyword ( text , slice ) {
1102
+ var result = '' ;
1103
+ var prevEnd = slice . start ;
1104
+ slice . hits . forEach ( function ( hit ) {
1105
+ result += text . substring ( prevEnd , hit . position ) ;
1106
+ var end = hit . position + hit . length ;
1107
+ result += '<b class="search-keyword">' + text . substring ( hit . position , end ) + '</b>' ;
1108
+ prevEnd = end ;
992
1109
} ) ;
1110
+ result += text . substring ( prevEnd , slice . end ) ;
1111
+ return result ;
1112
+ }
993
1113
994
- str += "<p class=\"search-result\">" + match_content + "...</p>"
1114
+ var resultItem = '' ;
1115
+
1116
+ if ( slicesOfTitle . length != 0 ) {
1117
+ resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword ( title , slicesOfTitle [ 0 ] ) + "</a>" ;
1118
+ } else {
1119
+ resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>" ;
995
1120
}
996
- str += "</li>" ;
1121
+
1122
+ slicesOfContent . forEach ( function ( slice ) {
1123
+ resultItem += "<a href='" + articleUrl + "'>" +
1124
+ "<p class=\"search-result\">" + highlightKeyword ( content , slice ) +
1125
+ "...</p>" + "</a>" ;
1126
+ } ) ;
1127
+
1128
+ resultItem += "</li>" ;
1129
+ resultItems . push ( {
1130
+ item : resultItem ,
1131
+ searchTextCount : searchTextCount ,
1132
+ hitCount : hitCount ,
1133
+ id : resultItems . length
1134
+ } ) ;
997
1135
}
998
- } ) } ;
999
- str += "</ul>" ;
1000
- if ( matchcounts == 0 ) { str = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>' }
1001
- if ( keywords == "" ) { str = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>' }
1002
- $resultContent . innerHTML = str ;
1003
- } ) ;
1136
+ } )
1137
+ } ;
1138
+ if ( keywords . length === 1 && keywords [ 0 ] === "" ) {
1139
+ resultContent . innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
1140
+ } else if ( resultItems . length === 0 ) {
1141
+ resultContent . innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
1142
+ } else {
1143
+ resultItems . sort ( function ( resultLeft , resultRight ) {
1144
+ if ( resultLeft . searchTextCount !== resultRight . searchTextCount ) {
1145
+ return resultRight . searchTextCount - resultLeft . searchTextCount ;
1146
+ } else if ( resultLeft . hitCount !== resultRight . hitCount ) {
1147
+ return resultRight . hitCount - resultLeft . hitCount ;
1148
+ } else {
1149
+ return resultRight . id - resultLeft . id ;
1150
+ }
1151
+ } ) ;
1152
+ var searchResultList = '<ul class=\"search-result-list\">' ;
1153
+ resultItems . forEach ( function ( result ) {
1154
+ searchResultList += result . item ;
1155
+ } )
1156
+ searchResultList += "</ul>" ;
1157
+ resultContent . innerHTML = searchResultList ;
1158
+ }
1159
+ }
1160
+
1161
+ if ( 'auto' === '' ) {
1162
+ input . addEventListener ( 'input' , inputEventFunction ) ;
1163
+ } else {
1164
+ $ ( '.search-icon' ) . click ( inputEventFunction ) ;
1165
+ input . addEventListener ( 'keypress' , function ( event ) {
1166
+ if ( event . keyCode === 13 ) {
1167
+ inputEventFunction ( ) ;
1168
+ }
1169
+ } ) ;
1170
+ }
1004
1171
proceedsearch ( ) ;
1005
1172
}
1006
1173
} ) ; }
1007
1174
1008
1175
// handle and trigger popup window;
1009
1176
$ ( '.popup-trigger' ) . click ( function ( e ) {
1010
1177
e . stopPropagation ( ) ;
1011
- if ( isfetched == false ) {
1178
+ if ( isfetched === false ) {
1012
1179
searchFunc ( path , 'local-search-input' , 'local-search-result' ) ;
1013
1180
} else {
1014
1181
proceedsearch ( ) ;
1015
1182
} ;
1016
1183
} ) ;
1017
1184
1018
- $ ( '.popup-btn-close' ) . click ( function ( e ) {
1019
- $ ( '.popup' ) . hide ( ) ;
1020
- $ ( ".local-search-pop-overlay" ) . remove ( ) ;
1021
- $ ( 'body' ) . css ( 'overflow' , '' ) ;
1022
- } ) ;
1185
+ $ ( '.popup-btn-close' ) . click ( onPopupClose ) ;
1023
1186
$ ( '.popup' ) . click ( function ( e ) {
1024
1187
e . stopPropagation ( ) ;
1025
1188
} ) ;
1189
+ $ ( document ) . on ( 'keyup' , function ( event ) {
1190
+ var shouldDismissSearchPopup = event . which === 27 &&
1191
+ $ ( '.search-popup' ) . is ( ':visible' ) ;
1192
+ if ( shouldDismissSearchPopup ) {
1193
+ onPopupClose ( ) ;
1194
+ }
1195
+ } ) ;
1026
1196
</ script >
1027
1197
1028
1198
0 commit comments