Merge pull request #517 from mempool/simon/bisq-address-prefix-search
Handle the 'B' prefix in the search bar autocomplete on /bisq
This commit is contained in:
		
						commit
						3ffa60db1f
					
				| @ -1,7 +1,7 @@ | |||||||
| <form [formGroup]="searchForm" (submit)="searchForm.valid && search()" novalidate> | <form [formGroup]="searchForm" (submit)="searchForm.valid && search()" novalidate> | ||||||
|   <div class="d-flex"> |   <div class="d-flex"> | ||||||
|     <div class="search-box-container mr-2"> |     <div class="search-box-container mr-2"> | ||||||
|       <input #instance="ngbTypeahead" [ngbTypeahead]="typeaheadSearch" (selectItem)="itemSelected()" (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="TXID, block height, hash or address"> |       <input #instance="ngbTypeahead" [ngbTypeahead]="typeaheadSearchFn" (selectItem)="itemSelected()" (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="TXID, block height, hash or address"> | ||||||
|     </div> |     </div> | ||||||
|     <div> |     <div> | ||||||
|       <button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary"><fa-icon [icon]="['fas', 'search']" [fixedWidth]="true" i18n-title="search-form.search-title" title="Search"></fa-icon></button> |       <button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary"><fa-icon [icon]="['fas', 'search']" [fixedWidth]="true" i18n-title="search-form.search-title" title="Search"></fa-icon></button> | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import { Router } from '@angular/router'; | |||||||
| import { AssetsService } from 'src/app/services/assets.service'; | import { AssetsService } from 'src/app/services/assets.service'; | ||||||
| import { StateService } from 'src/app/services/state.service'; | import { StateService } from 'src/app/services/state.service'; | ||||||
| import { Observable, of, Subject, merge } from 'rxjs'; | import { Observable, of, Subject, merge } from 'rxjs'; | ||||||
| import { debounceTime, distinctUntilChanged, switchMap, filter, catchError } from 'rxjs/operators'; | import { debounceTime, distinctUntilChanged, switchMap, filter, catchError, map } from 'rxjs/operators'; | ||||||
| import { ElectrsApiService } from 'src/app/services/electrs-api.service'; | import { ElectrsApiService } from 'src/app/services/electrs-api.service'; | ||||||
| import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap'; | import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap'; | ||||||
| 
 | 
 | ||||||
| @ -18,11 +18,12 @@ export class SearchFormComponent implements OnInit { | |||||||
|   network = ''; |   network = ''; | ||||||
|   assets: object = {}; |   assets: object = {}; | ||||||
|   isSearching = false; |   isSearching = false; | ||||||
|  |   typeaheadSearchFn: ((text: Observable<string>) => Observable<readonly any[]>); | ||||||
| 
 | 
 | ||||||
|   searchForm: FormGroup; |   searchForm: FormGroup; | ||||||
|   @Output() searchTriggered = new EventEmitter(); |   @Output() searchTriggered = new EventEmitter(); | ||||||
| 
 | 
 | ||||||
|   regexAddress = /^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,87})$/; |   regexAddress = /^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[bB]?[a-z]{2,5}1[ac-hj-np-z02-9]{8,87})$/; | ||||||
|   regexBlockhash = /^[0]{8}[a-fA-F0-9]{56}$/; |   regexBlockhash = /^[0]{8}[a-fA-F0-9]{56}$/; | ||||||
|   regexTransaction = /^[a-fA-F0-9]{64}$/; |   regexTransaction = /^[a-fA-F0-9]{64}$/; | ||||||
|   regexBlockheight = /^[0-9]+$/; |   regexBlockheight = /^[0-9]+$/; | ||||||
| @ -31,21 +32,6 @@ export class SearchFormComponent implements OnInit { | |||||||
|   focus$ = new Subject<string>(); |   focus$ = new Subject<string>(); | ||||||
|   click$ = new Subject<string>(); |   click$ = new Subject<string>(); | ||||||
| 
 | 
 | ||||||
|   typeaheadSearch = (text$: Observable<string>) => { |  | ||||||
|     const debouncedText$ = text$.pipe(debounceTime(200), distinctUntilChanged()); |  | ||||||
|     const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen())); |  | ||||||
|     const inputFocus$ = this.focus$; |  | ||||||
| 
 |  | ||||||
|     return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$) |  | ||||||
|       .pipe( |  | ||||||
|         switchMap((text) => { |  | ||||||
|           if (!text.length) { return of([]); } |  | ||||||
|           return this.electrsApiService.getAddressesByPrefix$(text) |  | ||||||
|             .pipe(catchError(() => of([]))); |  | ||||||
|         }) |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|   constructor( |   constructor( | ||||||
|     private formBuilder: FormBuilder, |     private formBuilder: FormBuilder, | ||||||
|     private router: Router, |     private router: Router, | ||||||
| @ -55,11 +41,13 @@ export class SearchFormComponent implements OnInit { | |||||||
|   ) { } |   ) { } | ||||||
| 
 | 
 | ||||||
|   ngOnInit() { |   ngOnInit() { | ||||||
|  |     this.typeaheadSearchFn = this.typeaheadSearch; | ||||||
|     this.stateService.networkChanged$.subscribe((network) => this.network = network); |     this.stateService.networkChanged$.subscribe((network) => this.network = network); | ||||||
| 
 | 
 | ||||||
|     this.searchForm = this.formBuilder.group({ |     this.searchForm = this.formBuilder.group({ | ||||||
|       searchText: ['', Validators.required], |       searchText: ['', Validators.required], | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|     if (this.network === 'liquid') { |     if (this.network === 'liquid') { | ||||||
|       this.assetsService.getAssetsMinimalJson$ |       this.assetsService.getAssetsMinimalJson$ | ||||||
|         .subscribe((assets) => { |         .subscribe((assets) => { | ||||||
| @ -68,6 +56,37 @@ export class SearchFormComponent implements OnInit { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   typeaheadSearch = (text$: Observable<string>) => { | ||||||
|  |     const debouncedText$ = text$.pipe( | ||||||
|  |       map((text) => { | ||||||
|  |         if (this.network === 'bisq' && text.match(/^(b)[^c]/i)) { | ||||||
|  |           return text.substr(1); | ||||||
|  |         } | ||||||
|  |         return text; | ||||||
|  |       }), | ||||||
|  |       debounceTime(200), | ||||||
|  |       distinctUntilChanged() | ||||||
|  |     ); | ||||||
|  |     const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen())); | ||||||
|  |     const inputFocus$ = this.focus$; | ||||||
|  | 
 | ||||||
|  |     return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$) | ||||||
|  |       .pipe( | ||||||
|  |         switchMap((text) => { | ||||||
|  |           if (!text.length) { | ||||||
|  |             return of([]); | ||||||
|  |           } | ||||||
|  |           return this.electrsApiService.getAddressesByPrefix$(text).pipe(catchError(() => of([]))); | ||||||
|  |         }), | ||||||
|  |         map((result: string[]) => { | ||||||
|  |           if (this.network === 'bisq') { | ||||||
|  |             return result.map((address: string) => 'B' + address); | ||||||
|  |           } | ||||||
|  |           return result; | ||||||
|  |         }) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|   itemSelected() { |   itemSelected() { | ||||||
|     setTimeout(() => this.search()); |     setTimeout(() => this.search()); | ||||||
|   } |   } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user