@@ -144,6 +144,7 @@ interface ICodeSnippetDisplayProps {
144144 */
145145interface ICodeSnippetDisplayState {
146146 codeSnippets : ICodeSnippet [ ] ;
147+ matchIndices : { [ key : number ] : number [ ] } ;
147148 searchValue : string ;
148149 filterTags : string [ ] ;
149150}
@@ -161,6 +162,7 @@ export class CodeSnippetDisplay extends React.Component<
161162 super ( props ) ;
162163 this . state = {
163164 codeSnippets : this . props . codeSnippets ,
165+ matchIndices : { } ,
164166 searchValue : '' ,
165167 filterTags : [ ]
166168 } ;
@@ -271,56 +273,98 @@ export class CodeSnippetDisplay extends React.Component<
271273 } ;
272274
273275 // Create 6 dots drag/drop image on hover
274- private dragHoverStyle = ( id : string ) : void => {
275- const _id : number = parseInt ( id , 10 ) ;
276-
276+ private dragHoverStyle = ( id : number ) : void => {
277277 document
278278 . getElementsByClassName ( CODE_SNIPPET_DRAG_HOVER )
279- [ _id ] . classList . add ( CODE_SNIPPET_DRAG_HOVER_SELECTED ) ;
279+ [ id ] . classList . add ( CODE_SNIPPET_DRAG_HOVER_SELECTED ) ;
280280 } ;
281281
282282 // Remove 6 dots off hover
283- private dragHoverStyleRemove = ( id : string ) : void => {
284- const _id : number = parseInt ( id , 10 ) ;
283+ private dragHoverStyleRemove = ( id : number ) : void => {
285284 if ( document . getElementsByClassName ( CODE_SNIPPET_DRAG_HOVER ) ) {
286285 document
287286 . getElementsByClassName ( CODE_SNIPPET_DRAG_HOVER )
288- [ _id ] . classList . remove ( CODE_SNIPPET_DRAG_HOVER_SELECTED ) ;
287+ [ id ] . classList . remove ( CODE_SNIPPET_DRAG_HOVER_SELECTED ) ;
289288 }
290289 } ;
291290
292291 // Bold text in snippet name based on search
293292 private boldNameOnSearch = (
294- searchValue : string ,
293+ id : number ,
295294 language : string ,
296295 name : string
297296 ) : JSX . Element => {
298297 const displayName = language + name ;
299298
299+ // check if this snippet is one of the filtered snippets
300+ // console.log(displayName);
300301 if (
301- searchValue !== '' &&
302- displayName . toLowerCase ( ) . includes ( searchValue . toLowerCase ( ) )
302+ this . state . searchValue !== '' &&
303+ Object . keys ( this . state . matchIndices ) . includes ( id . toString ( ) )
303304 ) {
304- const startIndex : number = displayName
305- . toLowerCase ( )
306- . indexOf ( searchValue . toLowerCase ( ) ) ;
307-
308- const endIndex : number = startIndex + searchValue . length ;
305+ // remove space
306+ // const tempSearchValue = searchValue.replace(/ /g, '');
307+ // const char_list = tempSearchValue.split('');
308+
309+ // console.log(char_list);
310+ // // form regular expression
311+ // let re = '/';
312+ // for (const ch of char_list) {
313+ // re += ch + '.*';
314+ // }
315+ // re += '/g';
316+
317+ // console.log(re);
318+
319+ // const startIndex: number = displayName
320+ // .toLowerCase()
321+ // .indexOf(searchValue.toLowerCase());
322+
323+ // const endIndex: number = startIndex + searchValue.length;
324+
325+ const elements = [ ] ;
326+ const boldIndices = this . state . matchIndices [ id ] ;
327+ for ( const index of boldIndices ) {
328+ if ( index >= language . length ) {
329+ elements . push (
330+ < span > { displayName . substring ( language . length , index ) } </ span >
331+ ) ;
332+ elements . push (
333+ < mark className = { SEARCH_BOLD } >
334+ { displayName . substring ( index , index + 1 ) }
335+ </ mark >
336+ ) ;
337+ }
338+ }
309339
310- if ( endIndex <= language . length ) {
311- return < span > { name } </ span > ;
312- } else {
313- const start = displayName . substring ( language . length , startIndex ) ;
314- const bolded = displayName . substring ( startIndex , endIndex ) ;
315- const end = displayName . substring ( endIndex ) ;
316- return (
340+ if ( boldIndices [ - 1 ] < displayName . length ) {
341+ elements . push (
317342 < span >
318- { start }
319- < mark className = { SEARCH_BOLD } > { bolded } </ mark >
320- { end }
343+ { displayName . substring ( boldIndices [ - 1 ] + 1 , displayName . length ) }
321344 </ span >
322345 ) ;
323346 }
347+
348+ if ( elements . length === 0 ) {
349+ return < span > { name } </ span > ;
350+ } else {
351+ return < span > { elements } </ span > ;
352+ }
353+
354+ // if (endIndex <= language.length) {
355+ // return <span>{name}</span>;
356+ // } else {
357+ // const start = displayName.substring(language.length, startIndex);
358+ // const bolded = displayName.substring(startIndex, endIndex);
359+ // const end = displayName.substring(endIndex);
360+ // return (
361+ // <span>
362+ // {start}
363+ // <mark className={SEARCH_BOLD}>{bolded}</mark>
364+ // {end}
365+ // </span>
366+ // );
367+ // }
324368 }
325369 return < span onDoubleClick = { this . handleRenameSnippet } > { name } </ span > ;
326370 } ;
@@ -516,7 +560,7 @@ export class CodeSnippetDisplay extends React.Component<
516560 target . removeEventListener ( 'mouseup' , this . _evtMouseUp , true ) ;
517561
518562 return this . _drag . start ( clientX , clientY ) . then ( ( ) => {
519- this . dragHoverStyleRemove ( codeSnippet . id . toString ( ) ) ;
563+ this . dragHoverStyleRemove ( codeSnippet . id ) ;
520564 this . _drag = null ;
521565 this . _dragData = null ;
522566 } ) ;
@@ -532,9 +576,8 @@ export class CodeSnippetDisplay extends React.Component<
532576 }
533577
534578 //Set the position of the preview to be next to the snippet title.
535- private _setPreviewPosition ( id : string ) : void {
536- const intID = parseInt ( id , 10 ) ;
537- const realTarget = document . getElementsByClassName ( TITLE_CLASS ) [ intID ] ;
579+ private _setPreviewPosition ( id : number ) : void {
580+ const realTarget = document . getElementsByClassName ( TITLE_CLASS ) [ id ] ;
538581 // distDown is the number of pixels to shift the preview down
539582 let distDown : number = realTarget . getBoundingClientRect ( ) . top - 43 ;
540583 if ( realTarget . getBoundingClientRect ( ) . top > window . screen . height / 2 ) {
@@ -1047,7 +1090,7 @@ export class CodeSnippetDisplay extends React.Component<
10471090 // Render display of code snippet list
10481091 private renderCodeSnippet = (
10491092 codeSnippet : ICodeSnippet ,
1050- id : string
1093+ id : number
10511094 ) : JSX . Element => {
10521095 const buttonClasses = BUTTON_CLASS ;
10531096 const displayName = '[' + codeSnippet . language + '] ' + codeSnippet . name ;
@@ -1070,7 +1113,7 @@ export class CodeSnippetDisplay extends React.Component<
10701113 < div
10711114 key = { codeSnippet . name }
10721115 className = { CODE_SNIPPET_ITEM }
1073- id = { id }
1116+ id = { id . toString ( ) }
10741117 onMouseOver = { ( ) : void => {
10751118 this . dragHoverStyle ( id ) ;
10761119 } }
@@ -1081,7 +1124,7 @@ export class CodeSnippetDisplay extends React.Component<
10811124 < div
10821125 className = { CODE_SNIPPET_DRAG_HOVER }
10831126 title = "Drag to move"
1084- id = { id }
1127+ id = { id . toString ( ) }
10851128 onMouseDown = { ( event ) : void => {
10861129 this . handleDragSnippet ( event ) ;
10871130 } }
@@ -1091,7 +1134,7 @@ export class CodeSnippetDisplay extends React.Component<
10911134 onMouseEnter = { ( ) : void => {
10921135 showPreview (
10931136 {
1094- id : parseInt ( id , 10 ) ,
1137+ id : id ,
10951138 title : displayName ,
10961139 body : new PreviewHandler ( ) ,
10971140 codeSnippet : codeSnippet
@@ -1104,16 +1147,16 @@ export class CodeSnippetDisplay extends React.Component<
11041147 this . _evtMouseLeave ( ) ;
11051148 } }
11061149 >
1107- < div key = { displayName } className = { TITLE_CLASS } id = { id } >
1150+ < div key = { displayName } className = { TITLE_CLASS } id = { id . toString ( ) } >
11081151 < div
1109- id = { id }
1152+ id = { id . toString ( ) }
11101153 title = { codeSnippet . name }
11111154 className = { DISPLAY_NAME_CLASS }
11121155 >
11131156 { this . renderLanguageIcon ( codeSnippet . language ) }
1114- { this . boldNameOnSearch ( this . state . searchValue , language , name ) }
1157+ { this . boldNameOnSearch ( id , language , name ) }
11151158 </ div >
1116- < div className = { ACTION_BUTTONS_WRAPPER_CLASS } id = { id } >
1159+ < div className = { ACTION_BUTTONS_WRAPPER_CLASS } id = { id . toString ( ) } >
11171160 { actionButtons . map ( btn => {
11181161 return (
11191162 < button
@@ -1137,8 +1180,8 @@ export class CodeSnippetDisplay extends React.Component<
11371180 } ) }
11381181 </ div >
11391182 </ div >
1140- < div className = { CODE_SNIPPET_DESC } id = { id } >
1141- < p id = { id } > { `${ codeSnippet . description } ` } </ p >
1183+ < div className = { CODE_SNIPPET_DESC } id = { id . toString ( ) } >
1184+ < p id = { id . toString ( ) } > { `${ codeSnippet . description } ` } </ p >
11421185 </ div >
11431186 </ div >
11441187 </ div >
@@ -1152,6 +1195,7 @@ export class CodeSnippetDisplay extends React.Component<
11521195 if ( state . searchValue === '' && state . filterTags . length === 0 ) {
11531196 return {
11541197 codeSnippets : props . codeSnippets ,
1198+ matchIndices : { } ,
11551199 searchValue : '' ,
11561200 filterTags : [ ]
11571201 } ;
@@ -1170,20 +1214,100 @@ export class CodeSnippetDisplay extends React.Component<
11701214 } ) ;
11711215 return {
11721216 codeSnippets : newSnippets ,
1217+ matchIndices : state . matchIndices ,
11731218 searchValue : state . searchValue ,
11741219 filterTags : state . filterTags
11751220 } ;
11761221 }
11771222 return null ;
11781223 }
11791224
1225+ /**
1226+ * Return an object with the entry of (id, matched_indices)
1227+ * @param id unique id of snippet
1228+ * @param regex regular expression to match
1229+ * @param str name or language of the code snippet
1230+ * @param char_list list of characters searched
1231+ */
1232+ matchSnippet (
1233+ id : number ,
1234+ regex : RegExp ,
1235+ str : string ,
1236+ char_list : string [ ]
1237+ ) : [ number , number [ ] ] {
1238+ const matches : { [ key : string ] : number } = { } ;
1239+ let match = [ ] ;
1240+ while ( ( match = regex . exec ( str ) ) ) {
1241+ matches [ match [ 0 ] ] = regex . lastIndex - 1 ;
1242+ // console.log(match);
1243+ // console.log("match found at " + match.index);
1244+ }
1245+
1246+ console . log ( str ) ;
1247+
1248+ // Object.keys(matches).length
1249+ if ( Object . keys ( matches ) . length !== char_list . length ) {
1250+ return null ;
1251+ }
1252+
1253+ console . log ( matches ) ;
1254+ return [ id , Object . values ( matches ) ] ;
1255+ }
1256+
11801257 filterSnippets = ( searchValue : string , filterTags : string [ ] ) : void => {
1258+ // remove space
1259+ const tempSearchValue = searchValue . replace ( / / g, '' ) ;
1260+ const char_list = tempSearchValue . split ( '' ) ;
1261+
1262+ // form regular expression
1263+ // let re = '.*';
1264+ // for (const ch of char_list) {
1265+ // re += ch + '.*';
1266+ // }
1267+ let re = '[' ;
1268+ for ( const ch of char_list ) {
1269+ re += ch ;
1270+ }
1271+ re += ']' ;
1272+
1273+ const regex = new RegExp ( re , 'g' ) ;
1274+ // console.log(regex);
1275+
1276+ // const str = 'Pythonmost_frequent';
1277+
1278+ // let match = [];
1279+ // let match_index = [];
1280+ // while(match = regex.exec(str)) {
1281+ // match_index.push(match.index)
1282+ // // console.log(match);
1283+ // // console.log("match found at " + match.index);
1284+ // }
1285+
1286+ // if(match_index.length !== char_list.length){
1287+ // match_index = []
1288+ // }
1289+ // console.log(match_index);
1290+
1291+ // const found = [...'Pythonmost_frequent'.matchAll(regex)];
1292+ // console.log(found.index);
1293+
1294+ // TODO: filter codes nippet with regex!
11811295 // filter with search
1182- let filteredSnippets = this . props . codeSnippets . filter (
1183- codeSnippet =>
1184- codeSnippet . name . toLowerCase ( ) . includes ( searchValue . toLowerCase ( ) ) ||
1185- codeSnippet . language . toLowerCase ( ) . includes ( searchValue . toLowerCase ( ) )
1186- ) ;
1296+ const matchIndices : { [ key : number ] : number [ ] } = { } ;
1297+ let filteredSnippets = this . props . codeSnippets . filter ( codeSnippet => {
1298+ const matchIndex = this . matchSnippet (
1299+ codeSnippet . id ,
1300+ regex ,
1301+ codeSnippet . language + codeSnippet . name ,
1302+ char_list
1303+ ) ;
1304+ if ( matchIndex ) {
1305+ matchIndices [ matchIndex [ 0 ] ] = matchIndex [ 1 ] ;
1306+ }
1307+ return matchIndex ;
1308+ } ) ;
1309+ console . log ( filteredSnippets ) ;
1310+ console . log ( matchIndices ) ;
11871311
11881312 // filter with tags
11891313 if ( filterTags . length !== 0 ) {
@@ -1199,6 +1323,7 @@ export class CodeSnippetDisplay extends React.Component<
11991323
12001324 this . setState ( {
12011325 codeSnippets : filteredSnippets ,
1326+ matchIndices : matchIndices ,
12021327 searchValue : searchValue ,
12031328 filterTags : filterTags
12041329 } ) ;
@@ -1350,8 +1475,8 @@ export class CodeSnippetDisplay extends React.Component<
13501475 />
13511476 < div className = { CODE_SNIPPETS_CONTAINER } >
13521477 < div >
1353- { this . state . codeSnippets . map ( ( codeSnippet , id ) =>
1354- this . renderCodeSnippet ( codeSnippet , id . toString ( ) )
1478+ { this . state . codeSnippets . map ( codeSnippet =>
1479+ this . renderCodeSnippet ( codeSnippet , codeSnippet . id )
13551480 ) }
13561481 </ div >
13571482 </ div >
0 commit comments