implement search service
This commit is contained in:
parent
ada83aae8f
commit
4ab36bc8ee
2
jslib
2
jslib
|
@ -1 +1 @@
|
||||||
Subproject commit 4ca7a9709e9ccd0e67ce09309ae605f2057bf089
|
Subproject commit d917651d9f844dc07abf3e817073aa1e10213b9a
|
|
@ -174,9 +174,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/lunr": {
|
"@types/lunr": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.1.6.tgz",
|
||||||
"integrity": "sha512-esk3CG25hRtHsVHm+LOjiSFYdw8be3uIY653WUwR43Bro914HSimPgPpqgajkhTJ0awK3RQfaIxP7zvbtCpcyg==",
|
"integrity": "sha512-Bz6fUhX1llTa7ygQJN3ttoVkkrpW7xxSEP7D7OYFO/FCBKqKqruRUZtJzTtYA0GkQX13lxU5u+8LuCviJlAXkQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/mousetrap": {
|
"@types/mousetrap": {
|
||||||
|
@ -6648,9 +6648,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lunr": {
|
"lunr": {
|
||||||
"version": "2.1.6",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.1.tgz",
|
||||||
"integrity": "sha512-ydJpB8CX8cZ/VE+KMaYaFcZ6+o2LruM6NG76VXdflYTgluvVemz1lW4anE+pyBbLvxJHZdvD1Jy/fOqdzAEJog=="
|
"integrity": "sha1-ETYWorYC3cEJMqe/ik5uV+v+zfI="
|
||||||
},
|
},
|
||||||
"magic-string": {
|
"magic-string": {
|
||||||
"version": "0.22.5",
|
"version": "0.22.5",
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
"@ngtools/webpack": "1.10.2",
|
"@ngtools/webpack": "1.10.2",
|
||||||
"@types/chrome": "0.0.51",
|
"@types/chrome": "0.0.51",
|
||||||
"@types/jasmine": "^2.8.2",
|
"@types/jasmine": "^2.8.2",
|
||||||
"@types/lunr": "2.1.5",
|
"@types/lunr": "^2.1.6",
|
||||||
"@types/mousetrap": "^1.6.0",
|
"@types/mousetrap": "^1.6.0",
|
||||||
"@types/node": "8.0.19",
|
"@types/node": "8.0.19",
|
||||||
"@types/node-forge": "0.6.10",
|
"@types/node-forge": "0.6.10",
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
"angulartics2": "5.0.1",
|
"angulartics2": "5.0.1",
|
||||||
"core-js": "2.4.1",
|
"core-js": "2.4.1",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
"lunr": "2.1.6",
|
"lunr": "2.3.1",
|
||||||
"mousetrap": "1.6.1",
|
"mousetrap": "1.6.1",
|
||||||
"ngx-infinite-scroll": "0.8.4",
|
"ngx-infinite-scroll": "0.8.4",
|
||||||
"node-forge": "0.7.1",
|
"node-forge": "0.7.1",
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
UserService,
|
UserService,
|
||||||
} from 'jslib/services';
|
} from 'jslib/services';
|
||||||
import { ExportService } from 'jslib/services/export.service';
|
import { ExportService } from 'jslib/services/export.service';
|
||||||
|
import { SearchService } from 'jslib/services/search.service';
|
||||||
import { WebCryptoFunctionService } from 'jslib/services/webCryptoFunction.service';
|
import { WebCryptoFunctionService } from 'jslib/services/webCryptoFunction.service';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -44,6 +45,7 @@ import {
|
||||||
UserService as UserServiceAbstraction,
|
UserService as UserServiceAbstraction,
|
||||||
} from 'jslib/abstractions';
|
} from 'jslib/abstractions';
|
||||||
import { ExportService as ExportServiceAbstraction } from 'jslib/abstractions/export.service';
|
import { ExportService as ExportServiceAbstraction } from 'jslib/abstractions/export.service';
|
||||||
|
import { SearchService as SearchServiceAbstraction } from 'jslib/abstractions/search.service';
|
||||||
|
|
||||||
import { Analytics } from 'jslib/misc';
|
import { Analytics } from 'jslib/misc';
|
||||||
|
|
||||||
|
@ -90,6 +92,7 @@ export default class MainBackground {
|
||||||
containerService: ContainerService;
|
containerService: ContainerService;
|
||||||
auditService: AuditServiceAbstraction;
|
auditService: AuditServiceAbstraction;
|
||||||
exportService: ExportServiceAbstraction;
|
exportService: ExportServiceAbstraction;
|
||||||
|
searchService: SearchServiceAbstraction;
|
||||||
analytics: Analytics;
|
analytics: Analytics;
|
||||||
|
|
||||||
onUpdatedRan: boolean;
|
onUpdatedRan: boolean;
|
||||||
|
@ -129,7 +132,8 @@ export default class MainBackground {
|
||||||
this.userService = new UserService(this.tokenService, this.storageService);
|
this.userService = new UserService(this.tokenService, this.storageService);
|
||||||
this.settingsService = new SettingsService(this.userService, this.storageService);
|
this.settingsService = new SettingsService(this.userService, this.storageService);
|
||||||
this.cipherService = new CipherService(this.cryptoService, this.userService, this.settingsService,
|
this.cipherService = new CipherService(this.cryptoService, this.userService, this.settingsService,
|
||||||
this.apiService, this.storageService, this.i18nService, this.platformUtilsService);
|
this.apiService, this.storageService, this.i18nService, this.platformUtilsService,
|
||||||
|
() => this.searchService);
|
||||||
this.folderService = new FolderService(this.cryptoService, this.userService, this.apiService,
|
this.folderService = new FolderService(this.cryptoService, this.userService, this.apiService,
|
||||||
this.storageService, this.i18nService, this.cipherService);
|
this.storageService, this.i18nService, this.cipherService);
|
||||||
this.collectionService = new CollectionService(this.cryptoService, this.userService, this.storageService,
|
this.collectionService = new CollectionService(this.cryptoService, this.userService, this.storageService,
|
||||||
|
@ -139,6 +143,7 @@ export default class MainBackground {
|
||||||
await this.setIcon();
|
await this.setIcon();
|
||||||
await this.refreshBadgeAndMenu(true);
|
await this.refreshBadgeAndMenu(true);
|
||||||
});
|
});
|
||||||
|
this.searchService = new SearchService(this.cipherService, this.platformUtilsService);
|
||||||
this.syncService = new SyncService(this.userService, this.apiService, this.settingsService,
|
this.syncService = new SyncService(this.userService, this.apiService, this.settingsService,
|
||||||
this.folderService, this.cipherService, this.cryptoService, this.collectionService,
|
this.folderService, this.cipherService, this.cryptoService, this.collectionService,
|
||||||
this.storageService, this.messagingService, async (expired: boolean) => await this.logout(expired));
|
this.storageService, this.messagingService, async (expired: boolean) => await this.logout(expired));
|
||||||
|
|
|
@ -29,6 +29,7 @@ import { LockService } from 'jslib/abstractions/lock.service';
|
||||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SearchService } from 'jslib/abstractions/search.service';
|
||||||
import { SettingsService } from 'jslib/abstractions/settings.service';
|
import { SettingsService } from 'jslib/abstractions/settings.service';
|
||||||
import { StateService as StateServiceAbstraction } from 'jslib/abstractions/state.service';
|
import { StateService as StateServiceAbstraction } from 'jslib/abstractions/state.service';
|
||||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||||
|
@ -139,7 +140,8 @@ export function initFactory(i18nService: I18nService, storageService: StorageSer
|
||||||
{ provide: StorageService, useFactory: getBgService<StorageService>('storageService'), deps: [] },
|
{ provide: StorageService, useFactory: getBgService<StorageService>('storageService'), deps: [] },
|
||||||
{ provide: AppIdService, useFactory: getBgService<AppIdService>('appIdService'), deps: [] },
|
{ provide: AppIdService, useFactory: getBgService<AppIdService>('appIdService'), deps: [] },
|
||||||
{ provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] },
|
{ provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] },
|
||||||
{ provide: ExportService, useFactory: getBgService<AppIdService>('exportService'), deps: [] },
|
{ provide: ExportService, useFactory: getBgService<ExportService>('exportService'), deps: [] },
|
||||||
|
{ provide: SearchService, useFactory: getBgService<SearchService>('searchService'), deps: [] },
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
useFactory: initFactory,
|
useFactory: initFactory,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<input type="search" placeholder="{{searchPlaceholder || ('searchVault' | i18n)}}" id="search"
|
<input type="search" placeholder="{{searchPlaceholder || ('searchVault' | i18n)}}" id="search"
|
||||||
[(ngModel)]="searchText" appAutofocus>
|
[(ngModel)]="searchText" (input)="search(200)" appAutofocus>
|
||||||
<i class="fa fa-search"></i>
|
<i class="fa fa-search"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="right" *ngIf="showAdd">
|
<div class="right" *ngIf="showAdd">
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<content>
|
<content>
|
||||||
<ng-container *ngIf="(!isPaging() ? (ciphers | searchCiphers: searchText) : pagedCiphers) as filteredCiphers">
|
<ng-container *ngIf="(!isPaging() ? ciphers : pagedCiphers) as filteredCiphers">
|
||||||
<div class="no-items" *ngIf="!filteredCiphers.length">
|
<div class="no-items" *ngIf="!filteredCiphers.length">
|
||||||
<i class="fa fa-spinner fa-spin fa-3x" *ngIf="!loaded"></i>
|
<i class="fa fa-spinner fa-spin fa-3x" *ngIf="!loaded"></i>
|
||||||
<ng-container *ngIf="loaded">
|
<ng-container *ngIf="loaded">
|
||||||
|
|
|
@ -15,11 +15,11 @@ import {
|
||||||
|
|
||||||
import { BrowserApi } from '../../browser/browserApi';
|
import { BrowserApi } from '../../browser/browserApi';
|
||||||
|
|
||||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
|
||||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SearchService } from 'jslib/abstractions/search.service';
|
||||||
import { StateService } from 'jslib/abstractions/state.service';
|
import { StateService } from 'jslib/abstractions/state.service';
|
||||||
|
|
||||||
import { CipherType } from 'jslib/enums/cipherType';
|
import { CipherType } from 'jslib/enums/cipherType';
|
||||||
|
@ -40,7 +40,6 @@ const ComponentId = 'CiphersComponent';
|
||||||
})
|
})
|
||||||
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
|
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
|
||||||
groupingTitle: string;
|
groupingTitle: string;
|
||||||
searchText: string;
|
|
||||||
state: any;
|
state: any;
|
||||||
showAdd = true;
|
showAdd = true;
|
||||||
folderId: string = null;
|
folderId: string = null;
|
||||||
|
@ -52,14 +51,14 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
||||||
private preventSelected = false;
|
private preventSelected = false;
|
||||||
private pageSize = 100;
|
private pageSize = 100;
|
||||||
|
|
||||||
constructor(cipherService: CipherService, private route: ActivatedRoute,
|
constructor(searchService: SearchService, private route: ActivatedRoute,
|
||||||
private router: Router, private location: Location,
|
private router: Router, private location: Location,
|
||||||
private ngZone: NgZone, private broadcasterService: BroadcasterService,
|
private ngZone: NgZone, private broadcasterService: BroadcasterService,
|
||||||
private changeDetectorRef: ChangeDetectorRef, private stateService: StateService,
|
private changeDetectorRef: ChangeDetectorRef, private stateService: StateService,
|
||||||
private popupUtils: PopupUtilsService, private i18nService: I18nService,
|
private popupUtils: PopupUtilsService, private i18nService: I18nService,
|
||||||
private folderService: FolderService, private collectionService: CollectionService,
|
private folderService: FolderService, private collectionService: CollectionService,
|
||||||
private analytics: Angulartics2, private platformUtilsService: PlatformUtilsService) {
|
private analytics: Angulartics2, private platformUtilsService: PlatformUtilsService) {
|
||||||
super(cipherService);
|
super(searchService);
|
||||||
this.pageSize = platformUtilsService.isEdge() ? 25 : 100;
|
this.pageSize = platformUtilsService.isEdge() ? 25 : 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +187,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
||||||
}
|
}
|
||||||
|
|
||||||
isSearching() {
|
isSearching() {
|
||||||
return this.searchText != null && this.searchText.length > 1;
|
return !this.searchPending && this.searchService.isSearchable(this.searchText);
|
||||||
}
|
}
|
||||||
|
|
||||||
isPaging() {
|
isPaging() {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CipherView } from 'jslib/models/view/cipherView';
|
||||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SearchService } from 'jslib/abstractions/search.service';
|
||||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||||
|
|
||||||
import { AutofillService } from '../../services/abstractions/autofill.service';
|
import { AutofillService } from '../../services/abstractions/autofill.service';
|
||||||
|
@ -50,13 +51,15 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
|
||||||
private totpCode: string;
|
private totpCode: string;
|
||||||
private totpTimeout: number;
|
private totpTimeout: number;
|
||||||
private loadedTimeout: number;
|
private loadedTimeout: number;
|
||||||
|
private searchTimeout: number;
|
||||||
|
|
||||||
constructor(private platformUtilsService: PlatformUtilsService, private cipherService: CipherService,
|
constructor(private platformUtilsService: PlatformUtilsService, private cipherService: CipherService,
|
||||||
private popupUtilsService: PopupUtilsService, private autofillService: AutofillService,
|
private popupUtilsService: PopupUtilsService, private autofillService: AutofillService,
|
||||||
private analytics: Angulartics2, private toasterService: ToasterService,
|
private analytics: Angulartics2, private toasterService: ToasterService,
|
||||||
private i18nService: I18nService, private router: Router,
|
private i18nService: I18nService, private router: Router,
|
||||||
private ngZone: NgZone, private broadcasterService: BroadcasterService,
|
private ngZone: NgZone, private broadcasterService: BroadcasterService,
|
||||||
private changeDetectorRef: ChangeDetectorRef, private syncService: SyncService) { }
|
private changeDetectorRef: ChangeDetectorRef, private syncService: SyncService,
|
||||||
|
private searchService: SearchService) { }
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.showLeftHeader = !this.platformUtilsService.isSafari();
|
this.showLeftHeader = !this.platformUtilsService.isSafari();
|
||||||
|
@ -171,10 +174,15 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
searchVault() {
|
searchVault() {
|
||||||
if (this.searchText == null || this.searchText.length < 2) {
|
if (this.searchTimeout != null) {
|
||||||
|
clearTimeout(this.searchTimeout);
|
||||||
|
}
|
||||||
|
if (!this.searchService.isSearchable(this.searchText)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.searchTimeout = window.setTimeout(async () => {
|
||||||
this.router.navigate(['/tabs/vault'], { queryParams: { searchText: this.searchText } });
|
this.router.navigate(['/tabs/vault'], { queryParams: { searchText: this.searchText } });
|
||||||
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async load() {
|
private async load() {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<input type="search" placeholder="{{'searchVault' | i18n}}" id="search"
|
<input type="search" placeholder="{{'searchVault' | i18n}}" id="search"
|
||||||
[(ngModel)]="searchText" appAutofocus>
|
[(ngModel)]="searchText" (input)="search(200)" appAutofocus>
|
||||||
<i class="fa fa-search"></i>
|
<i class="fa fa-search"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<content>
|
<content>
|
||||||
<div class="no-items" *ngIf="!ciphers || !ciphers.length">
|
<div class="no-items" *ngIf="(!ciphers || !ciphers.length) && !showSearching()">
|
||||||
<i class="fa fa-spinner fa-spin fa-3x" *ngIf="!loaded"></i>
|
<i class="fa fa-spinner fa-spin fa-3x" *ngIf="!loaded"></i>
|
||||||
<ng-container *ngIf="loaded">
|
<ng-container *ngIf="loaded">
|
||||||
<i class="fa fa-frown-o fa-4x"></i>
|
<i class="fa fa-frown-o fa-4x"></i>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
<button (click)="addCipher()" class="btn block primary link">{{'addItem' | i18n}}</button>
|
<button (click)="addCipher()" class="btn block primary link">{{'addItem' | i18n}}</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="ciphers && ciphers.length && (!searchText || searchText.length < 2)">
|
<ng-container *ngIf="ciphers && ciphers.length && !showSearching()">
|
||||||
<div class="box list" *ngIf="favoriteCiphers">
|
<div class="box list" *ngIf="favoriteCiphers">
|
||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
{{'favorites' | i18n}}
|
{{'favorites' | i18n}}
|
||||||
|
@ -127,14 +127,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="ciphers && ciphers.length && searchText && searchText.length > 1 &&
|
<ng-container *ngIf="showSearching()">
|
||||||
(ciphers | searchCiphers: searchText) as searchedCiphers">
|
<div class="no-items" *ngIf="!ciphers || !ciphers.length">
|
||||||
<div class="no-items" *ngIf="!searchedCiphers.length">
|
|
||||||
<p>{{'noItemsInList' | i18n}}</p>
|
<p>{{'noItemsInList' | i18n}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="box list full-list" *ngIf="searchedCiphers.length > 0">
|
<div class="box list full-list" *ngIf="ciphers && ciphers.length > 0">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-ciphers-list [ciphers]="searchedCiphers" title="{{'viewItem' | i18n}}"
|
<app-ciphers-list [ciphers]="ciphers" title="{{'viewItem' | i18n}}"
|
||||||
(onSelected)="selectCipher($event)"
|
(onSelected)="selectCipher($event)"
|
||||||
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SearchService } from 'jslib/abstractions/search.service';
|
||||||
import { StateService } from 'jslib/abstractions/state.service';
|
import { StateService } from 'jslib/abstractions/state.service';
|
||||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||||
|
|
||||||
|
@ -51,11 +52,15 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
state: any;
|
state: any;
|
||||||
scopeState: any;
|
scopeState: any;
|
||||||
showLeftHeader = true;
|
showLeftHeader = true;
|
||||||
|
searchPending = false;
|
||||||
|
|
||||||
private loadedTimeout: number;
|
private loadedTimeout: number;
|
||||||
private selectedTimeout: number;
|
private selectedTimeout: number;
|
||||||
private preventSelected = false;
|
private preventSelected = false;
|
||||||
private noFolderListSize = 100;
|
private noFolderListSize = 100;
|
||||||
|
private searchTimeout: any = null;
|
||||||
|
private hasSearched = false;
|
||||||
|
private hasLoadedAllCiphers = false;
|
||||||
|
|
||||||
constructor(collectionService: CollectionService, folderService: FolderService,
|
constructor(collectionService: CollectionService, folderService: FolderService,
|
||||||
private cipherService: CipherService, private router: Router,
|
private cipherService: CipherService, private router: Router,
|
||||||
|
@ -63,7 +68,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
private changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute,
|
private changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute,
|
||||||
private stateService: StateService, private popupUtils: PopupUtilsService,
|
private stateService: StateService, private popupUtils: PopupUtilsService,
|
||||||
private syncService: SyncService, private analytics: Angulartics2,
|
private syncService: SyncService, private analytics: Angulartics2,
|
||||||
private platformUtilsService: PlatformUtilsService) {
|
private platformUtilsService: PlatformUtilsService, private searchService: SearchService) {
|
||||||
super(collectionService, folderService);
|
super(collectionService, folderService);
|
||||||
this.noFolderListSize = platformUtilsService.isEdge() ? 25 : 100;
|
this.noFolderListSize = platformUtilsService.isEdge() ? 25 : 100;
|
||||||
}
|
}
|
||||||
|
@ -146,8 +151,10 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadCiphers() {
|
async loadCiphers() {
|
||||||
this.ciphers = await this.cipherService.getAllDecrypted();
|
if (!this.hasLoadedAllCiphers) {
|
||||||
|
this.hasLoadedAllCiphers = !this.searchService.isSearchable(this.searchText);
|
||||||
|
}
|
||||||
|
await this.search(null);
|
||||||
let favoriteCiphers: CipherView[] = null;
|
let favoriteCiphers: CipherView[] = null;
|
||||||
let noFolderCiphers: CipherView[] = null;
|
let noFolderCiphers: CipherView[] = null;
|
||||||
const folderCounts = new Map<string, number>();
|
const folderCounts = new Map<string, number>();
|
||||||
|
@ -199,6 +206,28 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
this.collectionCounts = collectionCounts;
|
this.collectionCounts = collectionCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async search(timeout: number = null) {
|
||||||
|
this.searchPending = false;
|
||||||
|
if (this.searchTimeout != null) {
|
||||||
|
clearTimeout(this.searchTimeout);
|
||||||
|
}
|
||||||
|
if (timeout == null) {
|
||||||
|
this.hasSearched = this.searchService.isSearchable(this.searchText);
|
||||||
|
this.ciphers = await this.searchService.searchCiphers(this.searchText, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.searchPending = true;
|
||||||
|
this.searchTimeout = setTimeout(async () => {
|
||||||
|
this.hasSearched = this.searchService.isSearchable(this.searchText);
|
||||||
|
if (!this.hasLoadedAllCiphers && !this.hasSearched) {
|
||||||
|
await this.loadCiphers();
|
||||||
|
} else {
|
||||||
|
this.ciphers = await this.searchService.searchCiphers(this.searchText, null);
|
||||||
|
}
|
||||||
|
this.searchPending = false;
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
async selectType(type: CipherType) {
|
async selectType(type: CipherType) {
|
||||||
super.selectType(type);
|
super.selectType(type);
|
||||||
this.router.navigate(['/ciphers'], { queryParams: { type: type } });
|
this.router.navigate(['/ciphers'], { queryParams: { type: type } });
|
||||||
|
@ -243,6 +272,10 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
this.router.navigate(['/add-cipher']);
|
this.router.navigate(['/add-cipher']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showSearching() {
|
||||||
|
return this.hasSearched || (!this.searchPending && this.searchService.isSearchable(this.searchText));
|
||||||
|
}
|
||||||
|
|
||||||
private async saveState() {
|
private async saveState() {
|
||||||
this.state = {
|
this.state = {
|
||||||
scrollY: this.popupUtils.getContentScrollY(window),
|
scrollY: this.popupUtils.getContentScrollY(window),
|
||||||
|
|
Loading…
Reference in New Issue