From 1b7e57a320b82adc9b7e12ff4eee51a9cacd35c3 Mon Sep 17 00:00:00 2001 From: Kyle Kemp Date: Mon, 29 Apr 2024 10:19:27 -0500 Subject: [PATCH] closes #20 --- .../card-text/card-text.component.ts | 2 +- .../search-cards/search-cards.component.html | 46 +++--- .../search-cards/search-cards.component.ts | 150 +----------------- .../components/topbar/topbar.component.html | 3 +- .../components/topbar/topbar.component.ts | 30 +++- src/app/card/card.page.html | 2 +- src/app/faq/faq.page.html | 2 +- src/app/faq/faq.page.ts | 4 - src/app/home/home.page.ts | 4 +- src/app/search.service.ts | 127 +++++++++++++++ src/app/search/search.page.html | 5 +- src/app/search/search.page.ts | 42 +++-- src/app/sets/sets.page.html | 2 +- src/app/sets/sets.page.ts | 6 - src/app/syntax/syntax.page.html | 2 +- src/app/syntax/syntax.page.ts | 6 - 16 files changed, 216 insertions(+), 217 deletions(-) create mode 100644 src/app/search.service.ts diff --git a/src/app/_shared/components/card-text/card-text.component.ts b/src/app/_shared/components/card-text/card-text.component.ts index b922f24..37af430 100644 --- a/src/app/_shared/components/card-text/card-text.component.ts +++ b/src/app/_shared/components/card-text/card-text.component.ts @@ -23,7 +23,7 @@ export class CardTextComponent { } private fixText(): string { - return this.text().split('+').join('\\+').split('-').join('\\-'); + return (this.text() ?? '').split('+').join('\\+').split('-').join('\\-'); } private getCustomRenderer(): marked.Renderer { diff --git a/src/app/_shared/components/search-cards/search-cards.component.html b/src/app/_shared/components/search-cards/search-cards.component.html index 013a637..add64d0 100644 --- a/src/app/_shared/components/search-cards/search-cards.component.html +++ b/src/app/_shared/components/search-cards/search-cards.component.html @@ -1,19 +1,19 @@ -@if(displayTotal === 0) { +@if(searchService.displayTotal() === 0) {

No results found

For help using the search tool, check the help guide.

} -@if(displayTotal > 0) { +@if(searchService.displayTotal() > 0) { - {{ displayCurrent | number }} - {{ displayMaximum | number }} - of  {{ displayTotal | number }} {{ queryDesc }} + {{ searchService.displayCurrent() | number }} - {{ searchService.displayMaximum() | number }} + of  {{ searchService.displayTotal() | number }} {{ searchService.queryDesc() }} @@ -21,17 +21,18 @@

No results found

- @for(card of visibleCards; track card.id) { + @for(card of searchService.visibleCards(); track card.id) { - + } - @if(visibleCards.length > 4) { + @if(searchService.visibleCards().length > 4) { }
@@ -43,8 +44,8 @@

No results found

Cards as
- + Images Text @@ -52,36 +53,41 @@

No results found

Sorted by
- + Name ID Product - + Asc ↑ Desc ↓
- + « - + Previous - - Next {{ cardsPerPage }} + + Next {{ searchService.cardsPerPage }} - + » diff --git a/src/app/_shared/components/search-cards/search-cards.component.ts b/src/app/_shared/components/search-cards/search-cards.component.ts index f347f55..7c8f338 100644 --- a/src/app/_shared/components/search-cards/search-cards.component.ts +++ b/src/app/_shared/components/search-cards/search-cards.component.ts @@ -1,23 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { - Component, - effect, - inject, - input, - output, - ViewChild, -} from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { DatatableComponent, SelectionType } from '@siemens/ngx-datatable'; -import { sortBy } from 'lodash'; +import { Component, inject, output } from '@angular/core'; -import { type ICard } from '../../../../../interfaces'; -import { queryToText } from '../../../../../search/search'; -import { CardsService } from '../../../cards.service'; - -type QueryDisplay = 'images' | 'text'; -type QuerySort = keyof ICard; -type QuerySortBy = 'asc' | 'desc'; +import { ActivatedRoute } from '@angular/router'; +import { SearchService } from '../../../search.service'; @Component({ selector: 'app-search-cards', @@ -25,139 +10,16 @@ type QuerySortBy = 'asc' | 'desc'; styleUrls: ['./search-cards.component.scss'], }) export class SearchCardsComponent { - private router = inject(Router); private route = inject(ActivatedRoute); - private cardsService = inject(CardsService); - - @ViewChild(DatatableComponent) table!: DatatableComponent; - - private queryValue = ''; - public queryDisplayValue: QueryDisplay = 'images'; - public querySortValue: QuerySort = 'name'; - public querySortByValue: QuerySortBy = 'asc'; - public pageValue = 0; - - public query = input(''); - public queryDisplay = input('images'); - public querySort = input('name'); - public querySortBy = input('asc'); - public page = input(0); + private searchService = inject(SearchService); public pageChanged = output(); public queryDesc = ''; - public readonly cardsPerPage = 60; - public totalPages = 0; - public queriedCards: ICard[] = []; - public visibleCards: ICard[] = []; - - public displayCurrent = 0; - public displayTotal = 0; - public displayMaximum = 0; - - public selected: any[] = []; - public expanded: any = {}; - public checkboxSelectionType: SelectionType = SelectionType.checkbox; - - constructor() { - effect(() => { - this.queryValue = this.query(); - this.queryDisplayValue = this.queryDisplay(); - this.querySortValue = this.querySort(); - this.querySortByValue = this.querySortBy(); - this.pageValue = this.page(); - - this.search(this.queryValue, false); - this.changePage(this.pageValue); - }); - } - - redoCurrentSearch() { - this.search(this.queryValue); - } - - search(query: string, changePage = true) { - this.queryValue = query; - this.pageValue = 0; - this.totalPages = 0; - this.displayCurrent = 0; - this.displayTotal = 0; - this.displayMaximum = 0; - - if (!this.query) { - this.queriedCards = []; - this.visibleCards = []; - this.updateParams(); - return; - } - - this.queryDesc = queryToText(this.queryValue); - - this.queriedCards = this.cardsService.searchCards(this.queryValue); - this.doExtraSorting(); - - if (changePage) { - this.changePage(0); - } - } - - updateParams() { - if (!this.queryValue) { - return; - } - - this.router.navigate([], { - relativeTo: this.route, - queryParams: { - q: this.queryValue, - d: this.queryDisplayValue, - s: this.querySortValue, - b: this.querySortByValue, - p: this.pageValue, - }, - queryParamsHandling: 'merge', - }); - } - - doExtraSorting() { - this.queriedCards = sortBy(this.queriedCards, this.querySortValue); - if (this.querySortByValue === 'desc') { - this.queriedCards = this.queriedCards.reverse(); - } - } - changePage(newPage: number) { - this.pageValue = newPage; - this.totalPages = - Math.ceil(this.queriedCards.length / this.cardsPerPage) - 1; - - if (this.pageValue > this.totalPages) { - this.pageValue = this.totalPages; - } - - if (this.pageValue < 0) { - this.pageValue = 0; - } - - this.visibleCards = this.queriedCards.slice( - this.pageValue * this.cardsPerPage, - (this.pageValue + 1) * this.cardsPerPage - ); - - this.displayCurrent = this.pageValue * this.cardsPerPage + 1; - this.displayTotal = this.queriedCards.length; - this.displayMaximum = Math.min( - this.displayTotal, - (this.pageValue + 1) * this.cardsPerPage - ); - - this.updateParams(); - this.pageChanged.emit(this.pageValue); - } - - select({ selected }: any) { - this.selected = [...selected]; + this.searchService.changePage(newPage); + this.pageChanged.emit(newPage); } public getDetailHeight(): any { diff --git a/src/app/_shared/components/topbar/topbar.component.html b/src/app/_shared/components/topbar/topbar.component.html index d3fc88d..ec7d375 100644 --- a/src/app/_shared/components/topbar/topbar.component.html +++ b/src/app/_shared/components/topbar/topbar.component.html @@ -13,8 +13,7 @@ } @if(showSearch()) { - + }
diff --git a/src/app/_shared/components/topbar/topbar.component.ts b/src/app/_shared/components/topbar/topbar.component.ts index 61483e0..e07e6ef 100644 --- a/src/app/_shared/components/topbar/topbar.component.ts +++ b/src/app/_shared/components/topbar/topbar.component.ts @@ -1,4 +1,6 @@ -import { Component, input, output } from '@angular/core'; +import { Component, inject, input } from '@angular/core'; +import { Router } from '@angular/router'; +import { SearchService } from '../../../search.service'; @Component({ selector: 'app-topbar', @@ -6,10 +8,32 @@ import { Component, input, output } from '@angular/core'; styleUrls: ['./topbar.component.scss'], }) export class TopbarComponent { + private router = inject(Router); + private searchService = inject(SearchService); + public title = input(''); public showSearch = input(true); public query = input(''); - public type = output(); - public enter = output(); + public searchOnType = input(false); + public searchOnEnter = input(false); + + doType($event: string) { + if (!this.searchOnType()) return; + this.search($event); + } + + doEnter($event: string) { + if (!this.searchOnEnter()) return; + this.search($event); + } + + private search(query: string) { + this.router.navigate(['/search'], { + queryParamsHandling: 'merge', + queryParams: { q: query }, + }); + + this.searchService.search(query); + } } diff --git a/src/app/card/card.page.html b/src/app/card/card.page.html index 68347ba..371b037 100644 --- a/src/app/card/card.page.html +++ b/src/app/card/card.page.html @@ -1,5 +1,5 @@ - + diff --git a/src/app/faq/faq.page.html b/src/app/faq/faq.page.html index 72c175c..291294f 100644 --- a/src/app/faq/faq.page.html +++ b/src/app/faq/faq.page.html @@ -1,5 +1,5 @@ - + diff --git a/src/app/faq/faq.page.ts b/src/app/faq/faq.page.ts index aba34c7..07e7c62 100644 --- a/src/app/faq/faq.page.ts +++ b/src/app/faq/faq.page.ts @@ -47,8 +47,4 @@ export class FaqPage { this.locale.set(faq.locale); this.productId.set(faq.productId); } - - search(query: string) { - this.router.navigate(['/search'], { queryParams: { q: query } }); - } } diff --git a/src/app/home/home.page.ts b/src/app/home/home.page.ts index 8a6a515..84238ca 100644 --- a/src/app/home/home.page.ts +++ b/src/app/home/home.page.ts @@ -12,6 +12,8 @@ export class HomePage { public searchQuery = ''; search(query: string) { - this.router.navigate(['/search'], { queryParams: { q: query } }); + this.router.navigate(['/search'], { + queryParams: { q: query }, + }); } } diff --git a/src/app/search.service.ts b/src/app/search.service.ts new file mode 100644 index 0000000..af8d2cc --- /dev/null +++ b/src/app/search.service.ts @@ -0,0 +1,127 @@ +import { inject, Injectable, signal } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { sortBy } from 'lodash'; +import type { ICard } from '../../interfaces'; +import { queryToText } from '../../search/search'; +import { CardsService } from './cards.service'; + +export type QueryDisplay = 'images' | 'text'; +export type QuerySort = keyof ICard; +export type QuerySortBy = 'asc' | 'desc'; + +@Injectable({ + providedIn: 'root', +}) +export class SearchService { + private router = inject(Router); + private route = inject(ActivatedRoute); + private cardsService = inject(CardsService); + + public visibleCards = signal([]); + public queryDesc = signal(''); + + public readonly cardsPerPage = 60; + public queriedCards: ICard[] = []; + + public totalPages = signal(0); + public pageValue = signal(0); + + public displayCurrent = signal(0); + public displayTotal = signal(0); + public displayMaximum = signal(0); + + private queryValue = ''; + + public queryDisplayValue: QueryDisplay = 'images'; + public querySortValue: QuerySort = 'name'; + public querySortByValue: QuerySortBy = 'asc'; + + search(query: string, changePage = true) { + this.queryValue = query; + this.pageValue.set(0); + this.totalPages.set(0); + this.displayCurrent.set(0); + this.displayTotal.set(0); + this.displayMaximum.set(0); + + if (!this.queryValue) { + this.queriedCards = []; + this.visibleCards.set([]); + this.updateParams(); + return; + } + + this.queryDesc.set(queryToText(this.queryValue)); + + this.queriedCards = this.cardsService.searchCards(this.queryValue); + this.doExtraSorting(); + + if (changePage) { + this.changePage(0); + } + } + + redoCurrentSearch() { + this.updateParams(); + this.search(this.queryValue); + } + + changePage(newPage: number) { + this.pageValue.set(newPage); + this.totalPages.set( + Math.ceil(this.queriedCards.length / this.cardsPerPage) - 1 + ); + + if (this.pageValue() > this.totalPages()) { + this.pageValue.set(this.totalPages()); + } + + if (this.pageValue() < 0) { + this.pageValue.set(0); + } + + this.visibleCards.set( + this.queriedCards.slice( + this.pageValue() * this.cardsPerPage, + (this.pageValue() + 1) * this.cardsPerPage + ) + ); + + this.displayCurrent.set(this.pageValue() * this.cardsPerPage + 1); + this.displayTotal.set(this.queriedCards.length); + this.displayMaximum.set( + Math.min(this.displayTotal(), (this.pageValue() + 1) * this.cardsPerPage) + ); + + this.updateParams(); + } + + private updateParams() { + if (!this.queryValue) { + return; + } + + this.router.navigate([], { + relativeTo: this.route, + queryParams: { + q: this.queryValue, + d: this.queryDisplayValue, + s: this.querySortValue, + b: this.querySortByValue, + p: this.pageValue(), + }, + queryParamsHandling: 'merge', + }); + } + + private doExtraSorting() { + this.queriedCards = sortBy(this.queriedCards, this.querySortValue); + if (this.querySortByValue === 'desc') { + this.queriedCards = this.queriedCards.reverse(); + } + } + + public resetCards() { + this.visibleCards.set([]); + } +} diff --git a/src/app/search/search.page.html b/src/app/search/search.page.html index b1677a2..7df8402 100644 --- a/src/app/search/search.page.html +++ b/src/app/search/search.page.html @@ -1,11 +1,10 @@ - +
- +
diff --git a/src/app/search/search.page.ts b/src/app/search/search.page.ts index ccbd58a..b6b3873 100644 --- a/src/app/search/search.page.ts +++ b/src/app/search/search.page.ts @@ -1,8 +1,12 @@ -import { Component, inject, ViewChild } from '@angular/core'; +import { Component, inject } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { DatatableComponent } from '@siemens/ngx-datatable'; -import { type ICard } from '../../../interfaces'; +import { + SearchService, + type QueryDisplay, + type QuerySort, + type QuerySortBy, +} from '../search.service'; @Component({ selector: 'app-search', @@ -11,32 +15,24 @@ import { type ICard } from '../../../interfaces'; }) export class SearchPage { private route = inject(ActivatedRoute); - - @ViewChild(DatatableComponent) table!: DatatableComponent; + private searchService = inject(SearchService); public query = ''; - public queryDisplay: 'images' | 'text' = 'images'; - public querySort: keyof ICard = 'name'; - public querySortBy: 'asc' | 'desc' = 'asc'; public page = 0; ionViewDidEnter() { this.query = this.route.snapshot.queryParamMap.get('q') || ''; - this.queryDisplay = - (this.route.snapshot.queryParamMap.get('d') as 'images' | 'text') || - 'images'; - this.querySort = - (this.route.snapshot.queryParamMap.get('s') as keyof ICard) || 'name'; - this.querySortBy = - (this.route.snapshot.queryParamMap.get('b') as 'asc' | 'desc') || 'asc'; - - this.page = parseInt(this.route.snapshot.queryParamMap.get('p') || '0', 10); - - this.search(this.query); - } - - search(query: string) { - this.query = query; + this.searchService.queryDisplayValue = + (this.route.snapshot.queryParamMap.get('d') as QueryDisplay) || 'images'; + this.searchService.querySortValue = + (this.route.snapshot.queryParamMap.get('s') as QuerySort) || 'name'; + this.searchService.querySortByValue = + (this.route.snapshot.queryParamMap.get('b') as QuerySortBy) || 'asc'; + this.searchService.pageValue.set( + parseInt(this.route.snapshot.queryParamMap.get('p') || '0', 10) + ); + + this.searchService.search(this.query); } } diff --git a/src/app/sets/sets.page.html b/src/app/sets/sets.page.html index 2399130..39ac96e 100644 --- a/src/app/sets/sets.page.html +++ b/src/app/sets/sets.page.html @@ -1,5 +1,5 @@ - + diff --git a/src/app/sets/sets.page.ts b/src/app/sets/sets.page.ts index 1d9eaf2..24bad55 100644 --- a/src/app/sets/sets.page.ts +++ b/src/app/sets/sets.page.ts @@ -1,6 +1,5 @@ import { HttpClient } from '@angular/common/http'; import { Component, inject, type OnInit } from '@angular/core'; -import { Router } from '@angular/router'; import { sortBy } from 'lodash'; import { type IProduct } from '../../../interfaces'; import { environment } from '../../environments/environment'; @@ -11,7 +10,6 @@ import { environment } from '../../environments/environment'; styleUrls: ['./sets.page.scss'], }) export class SetsPage implements OnInit { - private router = inject(Router); private http = inject(HttpClient); public allProducts: IProduct[] = []; @@ -27,8 +25,4 @@ export class SetsPage implements OnInit { formatSetNameForSearch(productId: string, subproductId: string): string { return `product:"${productId}" subproduct:"${subproductId}"`; } - - search(query: string) { - this.router.navigate(['/search'], { queryParams: { q: query } }); - } } diff --git a/src/app/syntax/syntax.page.html b/src/app/syntax/syntax.page.html index dcae3ba..7486b5a 100644 --- a/src/app/syntax/syntax.page.html +++ b/src/app/syntax/syntax.page.html @@ -1,5 +1,5 @@ - + diff --git a/src/app/syntax/syntax.page.ts b/src/app/syntax/syntax.page.ts index 950765e..7b5b175 100644 --- a/src/app/syntax/syntax.page.ts +++ b/src/app/syntax/syntax.page.ts @@ -1,6 +1,5 @@ import { Component, inject, type OnInit } from '@angular/core'; import { DomSanitizer, type SafeHtml } from '@angular/platform-browser'; -import { Router } from '@angular/router'; import { marked } from 'marked'; @@ -20,7 +19,6 @@ import { styleUrls: ['./syntax.page.scss'], }) export class SyntaxPage implements OnInit { - private router = inject(Router); private domSanitizer = inject(DomSanitizer); public allOperators: ICardHelp[] = [ @@ -39,10 +37,6 @@ export class SyntaxPage implements OnInit { } } - search(query: string) { - this.router.navigate(['/search'], { queryParams: { q: query } }); - } - formatText(text: string): SafeHtml { return this.domSanitizer.bypassSecurityTrustHtml(marked.parse(text)); }