Improved search-replace component logic by disabing buttons when no query; displaying found/not found status; displaying too long query; adding ctrl-up and down key bindig on query field to god prev-next instance found

This commit is contained in:
2025-11-23 00:49:44 -06:00
parent 8b47ff3919
commit 9f201a3dac
3 changed files with 77 additions and 29 deletions

0
list.m3u8 Normal file
View File

View File

@@ -1,7 +1,20 @@
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<div class="col col-3"> <div class="col col-3">
<label id="find-status-lbl">Find in Current File</label> @if (isQueryLong) {
<label id="find-status-lbl">
<b class="error">Query exceeds 80 characters...</b>
</label>
} @else if (isQueryNotFound) {
<label id="find-status-lbl">
<b class="warning">Query not found...</b>
<p class="warning" style="white-space: pre;">{{query}}</p>
</label>
} @else if (!isQueryLong && !isQueryNotFound) {
<label id="find-status-lbl">Find in Current File:
<p class="success">{{query}}</p>
</label>
}
</div> </div>
<div class="col col-4"> <div class="col col-4">
@@ -45,15 +58,27 @@
id="find-entry" id="find-entry"
class="form-control" class="form-control"
type="search" type="search"
(keyup)="searchForString()" (focus)="searchForString()"
(keyup)="findEntryKeyUpHandler($event)"
(input)="searchForString()"
placeholder="Find in current file..." placeholder="Find in current file..."
aria-label="Find in current file..." aria-label="Find in current file..."
/> />
</div> </div>
</div> </div>
<div class="col col-auto"> <div class="col col-auto">
<button id="find-btn" class="width-8em btn btn-sm btn-dark" (click)="findNextEntry()">Find</button> <button
<button id="find-all-btn" class="width-8em btn btn-sm btn-dark" (click)="findAllEntries()">Find All</button> [disabled]="!query || isQueryLong || isQueryNotFound"
id="find-btn"
class="width-8em btn btn-sm btn-dark"
(click)="findNextEntry()">Find
</button>
<button
[disabled]="!query || isQueryLong || isQueryNotFound"
id="find-all-btn"
class="width-8em btn btn-sm btn-dark"
(click)="findAllEntries()">Find All
</button>
</div> </div>
</div> </div>
</div> </div>
@@ -68,15 +93,25 @@
id="replace-entry" id="replace-entry"
class="form-control" class="form-control"
type="search" type="search"
(keyup)="replaceEntry($event)" (keyup.enter)="replaceEntry($event)"
title="Replace in current file..." title="Replace in current file..."
placeholder="Replace in current file..." placeholder="Replace in current file..."
/> />
</div> </div>
</div> </div>
<div class="col col-auto"> <div class="col col-auto">
<button id="replace-btn" class="width-8em btn btn-sm btn-dark" (click)="replaceEntry($event)">Replace</button> <button
<button id="replace-all-btn" class="width-8em btn btn-sm btn-dark" (click)="replaceAll()">Replace All</button> [disabled]="!query || isQueryLong || isQueryNotFound"
id="replace-btn"
class="width-8em btn btn-sm btn-dark"
(click)="replaceEntry($event)">Replace
</button>
<button
[disabled]="!query || isQueryLong || isQueryNotFound"
id="replace-all-btn"
class="width-8em btn btn-sm btn-dark"
(click)="replaceAll()">Replace All
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -36,15 +36,18 @@ export class SearchReplaceComponent {
@ViewChild('findEntryElm') findEntryElm!: ElementRef; @ViewChild('findEntryElm') findEntryElm!: ElementRef;
@ViewChild('replaceEntryElm') replaceEntryElm!: ElementRef; @ViewChild('replaceEntryElm') replaceEntryElm!: ElementRef;
@Input() query: string = "";
@Input() findOptions: string = "";
@Input() isQueryLong: boolean = false;
@Input() isQueryNotFound: boolean = false;
private editor!: any; private editor!: any;
@Input() findOptions: string = "";
private useWholeWordSearch: boolean = false; private useWholeWordSearch: boolean = false;
private searchOnlyInSelection: boolean = false; private searchOnlyInSelection: boolean = false;
private useCaseSensitive: boolean = false; private useCaseSensitive: boolean = false;
private useRegex: boolean = false; private useRegex: boolean = false;
private selection: string = ""; private selection: string = "";
private query: string = "";
private toStr: string = ""; private toStr: string = "";
private isBackwards: boolean = false; private isBackwards: boolean = false;
private isWrap: boolean = true; private isWrap: boolean = true;
@@ -179,16 +182,24 @@ export class SearchReplaceComponent {
this.findOptions = findOptionsStr; this.findOptions = findOptionsStr;
} }
public findPreviousEntry() {
this.editor.findPrevious();
}
public findNextEntry() { public findNextEntry() {
this.editor.findNext(); this.editor.findNext();
} }
public findEntryKeyUpHandler(event: KeyboardEvent) {
if (!event.ctrlKey || !this.query) return;
if (event.key === "ArrowUp") this.findPreviousEntry();
if (event.key === "ArrowDown") this.findNextEntry();
}
public findAllEntries() { public findAllEntries() {
this.query = this.findEntryElm.nativeElement.value; this.query = this.findEntryElm.nativeElement.value;
if (!this.query) return;
let totalCount = this.editor.findAll(this.query, { let totalCount = this.editor.findAll(this.query, {
backwards: this.isBackwards, backwards: this.isBackwards,
wrap: this.isWrap, wrap: this.isWrap,
@@ -197,18 +208,12 @@ export class SearchReplaceComponent {
regExp: this.useRegex, regExp: this.useRegex,
range: this.searchOnlyInSelection range: this.searchOnlyInSelection
}); });
if (totalCount === 0) this.isQueryNotFound = true;
} }
public findPreviousEntry() { public replaceEntry(event: KeyboardEvent) {
this.editor.findPrevious(); if (this.isQueryLong || this.isQueryNotFound) return;
}
public replaceEntry(event: any) {
if (event instanceof KeyboardEvent) {
if (event.key !== "Enter") {
return;
}
}
let fromStr = this.findEntryElm.nativeElement.value; let fromStr = this.findEntryElm.nativeElement.value;
let toStr = this.replaceEntryElm.nativeElement.value; let toStr = this.replaceEntryElm.nativeElement.value;
@@ -229,6 +234,8 @@ export class SearchReplaceComponent {
} }
public replaceAll() { public replaceAll() {
if (this.isQueryLong || this.isQueryNotFound) return;
let fromStr = this.findEntryElm.nativeElement.value; let fromStr = this.findEntryElm.nativeElement.value;
let toStr = this.replaceEntryElm.nativeElement.value; let toStr = this.replaceEntryElm.nativeElement.value;
@@ -242,23 +249,27 @@ export class SearchReplaceComponent {
regExp: this.useRegex, regExp: this.useRegex,
range: this.searchOnlyInSelection range: this.searchOnlyInSelection
}); });
this.isQueryNotFound = true;
} }
public searchForString() { public searchForString() {
if (event instanceof KeyboardEvent) { if (this.searchTimeoutId) { clearTimeout(this.searchTimeoutId); }
if (event.key !== "Enter") {
return;
}
}
this.query = this.findEntryElm.nativeElement.value; this.query = this.findEntryElm.nativeElement.value;
if (!this.query) return; if (!this.query) {
this.isQueryLong = false;
this.isQueryNotFound = false;
if (this.searchTimeoutId) { clearTimeout(this.searchTimeoutId); } return;
}
this.isQueryLong = (this.query.length > 80);
if (this.isQueryLong) return;
this.searchTimeoutId = setTimeout(() => { this.searchTimeoutId = setTimeout(() => {
let totalCount = this.editor.find(this.query, { let totalCount = this.editor.findAll(this.query, {
backwards: this.isBackwards, backwards: this.isBackwards,
wrap: this.isWrap, wrap: this.isWrap,
caseSensitive: this.useCaseSensitive, caseSensitive: this.useCaseSensitive,
@@ -266,6 +277,8 @@ export class SearchReplaceComponent {
regExp: this.useRegex, regExp: this.useRegex,
range: this.searchOnlyInSelection range: this.searchOnlyInSelection
}); });
this.isQueryNotFound = (totalCount === 0);
}, this.searchTimeout); }, this.searchTimeout);
} }