manage state for vault pages
This commit is contained in:
parent
9d737f76d1
commit
a3fc1c8d30
|
@ -9,6 +9,7 @@ import {
|
||||||
OnInit,
|
OnInit,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
import {
|
||||||
|
NavigationEnd,
|
||||||
Router,
|
Router,
|
||||||
RouterOutlet,
|
RouterOutlet,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
@ -22,6 +23,7 @@ import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||||
|
|
||||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
import { StateService } from 'jslib/abstractions/state.service';
|
||||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||||
|
|
||||||
import { ConstantsService } from 'jslib/services/constants.service';
|
import { ConstantsService } from 'jslib/services/constants.service';
|
||||||
|
@ -49,11 +51,13 @@ export class AppComponent implements OnInit {
|
||||||
});
|
});
|
||||||
|
|
||||||
private lastActivity: number = null;
|
private lastActivity: number = null;
|
||||||
|
private previousUrl: string = '';
|
||||||
|
|
||||||
constructor(private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics, private analytics: Angulartics2,
|
constructor(private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics, private analytics: Angulartics2,
|
||||||
private toasterService: ToasterService, private storageService: StorageService,
|
private toasterService: ToasterService, private storageService: StorageService,
|
||||||
private broadcasterService: BroadcasterService, private authService: AuthService,
|
private broadcasterService: BroadcasterService, private authService: AuthService,
|
||||||
private i18nService: I18nService, private router: Router) { }
|
private i18nService: I18nService, private router: Router,
|
||||||
|
private stateService: StateService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
window.onmousemove = () => this.recordActivity();
|
window.onmousemove = () => this.recordActivity();
|
||||||
|
@ -80,6 +84,17 @@ export class AppComponent implements OnInit {
|
||||||
};
|
};
|
||||||
|
|
||||||
BrowserApi.messageListener((window as any).bitwardenPopupMainMessageListener);
|
BrowserApi.messageListener((window as any).bitwardenPopupMainMessageListener);
|
||||||
|
|
||||||
|
this.router.events.subscribe(event => {
|
||||||
|
if (event instanceof NavigationEnd) {
|
||||||
|
const url = event.urlAfterRedirects || event.url || '';
|
||||||
|
if (url.startsWith('/tabs/') && this.previousUrl.startsWith('/tabs/')) {
|
||||||
|
this.stateService.remove('GroupingsComponent');
|
||||||
|
this.stateService.remove('CiphersComponent');
|
||||||
|
}
|
||||||
|
this.previousUrl = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getState(outlet: RouterOutlet) {
|
getState(outlet: RouterOutlet) {
|
||||||
|
|
|
@ -18,4 +18,16 @@ export class PopupUtilsService {
|
||||||
return win.location.search === '' || win.location.search.indexOf('uilocation=') === -1 ||
|
return win.location.search === '' || win.location.search.indexOf('uilocation=') === -1 ||
|
||||||
win.location.search.indexOf('uilocation=popup') > -1;
|
win.location.search.indexOf('uilocation=popup') > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getContentScrollY(win: Window): number {
|
||||||
|
const content = win.document.getElementsByTagName('content')[0];
|
||||||
|
return content.scrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentScrollY(win: Window, scrollY: number): void {
|
||||||
|
if (scrollY != null) {
|
||||||
|
const content = win.document.getElementsByTagName('content')[0];
|
||||||
|
content.scrollTop = scrollY;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,4 @@
|
||||||
import {
|
import { Component } from '@angular/core';
|
||||||
Component,
|
|
||||||
ComponentFactoryResolver,
|
|
||||||
NgZone,
|
|
||||||
OnDestroy,
|
|
||||||
OnInit,
|
|
||||||
Type,
|
|
||||||
ViewChild,
|
|
||||||
ViewContainerRef,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tabs',
|
selector: 'app-tabs',
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|
||||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||||
|
import { StateService } from 'jslib/abstractions/state.service';
|
||||||
|
|
||||||
import { CipherView } from 'jslib/models/view/cipherView';
|
import { CipherView } from 'jslib/models/view/cipherView';
|
||||||
|
|
||||||
|
@ -19,7 +20,9 @@ import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||||
|
|
||||||
import { CiphersComponent as BaseCiphersComponent } from 'jslib/angular/components/ciphers.component';
|
import { CiphersComponent as BaseCiphersComponent } from 'jslib/angular/components/ciphers.component';
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = 'CiphersComponent';
|
import { PopupUtilsService } from '../services/popup-utils.service';
|
||||||
|
|
||||||
|
const ComponentId = 'CiphersComponent';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vault-ciphers',
|
selector: 'app-vault-ciphers',
|
||||||
|
@ -27,11 +30,13 @@ const BroadcasterSubscriptionId = 'CiphersComponent';
|
||||||
})
|
})
|
||||||
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
|
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
|
||||||
searchText: string;
|
searchText: string;
|
||||||
|
state: any;
|
||||||
|
|
||||||
constructor(cipherService: CipherService, private route: ActivatedRoute,
|
constructor(cipherService: CipherService, 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 changeDetectorRef: ChangeDetectorRef, private stateService: StateService,
|
||||||
|
private popupUtils: PopupUtilsService) {
|
||||||
super(cipherService);
|
super(cipherService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +52,15 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
||||||
} else {
|
} else {
|
||||||
await super.load();
|
await super.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.state = (await this.stateService.get<any>(ComponentId)) || {};
|
||||||
|
if (this.state.searchText) {
|
||||||
|
this.searchText = this.state.searchText;
|
||||||
|
}
|
||||||
|
window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||||
this.ngZone.run(async () => {
|
this.ngZone.run(async () => {
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
case 'syncCompleted':
|
case 'syncCompleted':
|
||||||
|
@ -67,7 +78,8 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
this.saveState();
|
||||||
|
this.broadcasterService.unsubscribe(ComponentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectCipher(cipher: CipherView) {
|
selectCipher(cipher: CipherView) {
|
||||||
|
@ -83,4 +95,12 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
||||||
back() {
|
back() {
|
||||||
this.location.back();
|
this.location.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async saveState() {
|
||||||
|
this.state = {
|
||||||
|
scrollY: this.popupUtils.getContentScrollY(window),
|
||||||
|
searchText: this.searchText,
|
||||||
|
};
|
||||||
|
await this.stateService.save(ComponentId, this.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,15 @@ import { FolderView } from 'jslib/models/view/folderView';
|
||||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||||
|
import { StateService } from 'jslib/abstractions/state.service';
|
||||||
|
|
||||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||||
|
|
||||||
import { GroupingsComponent as BaseGroupingsComponent } from 'jslib/angular/components/groupings.component';
|
import { GroupingsComponent as BaseGroupingsComponent } from 'jslib/angular/components/groupings.component';
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = 'GroupingsComponent';
|
import { PopupUtilsService } from '../services/popup-utils.service';
|
||||||
|
|
||||||
|
const ComponentId = 'GroupingsComponent';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vault-groupings',
|
selector: 'app-vault-groupings',
|
||||||
|
@ -40,16 +43,20 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
typeCounts = new Map<CipherType, number>();
|
typeCounts = new Map<CipherType, number>();
|
||||||
showNoFolderCiphers = false;
|
showNoFolderCiphers = false;
|
||||||
searchText: string;
|
searchText: string;
|
||||||
|
state: any;
|
||||||
|
|
||||||
constructor(collectionService: CollectionService, folderService: FolderService,
|
constructor(collectionService: CollectionService, folderService: FolderService,
|
||||||
private cipherService: CipherService, private router: Router,
|
private cipherService: CipherService, private router: Router,
|
||||||
private ngZone: NgZone, private broadcasterService: BroadcasterService,
|
private ngZone: NgZone, private broadcasterService: BroadcasterService,
|
||||||
private changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute) {
|
private changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute,
|
||||||
|
private stateService: StateService, private popupUtils: PopupUtilsService) {
|
||||||
super(collectionService, folderService);
|
super(collectionService, folderService);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
this.stateService.remove('CiphersComponent');
|
||||||
|
|
||||||
|
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||||
this.ngZone.run(async () => {
|
this.ngZone.run(async () => {
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
case 'syncCompleted':
|
case 'syncCompleted':
|
||||||
|
@ -66,16 +73,21 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route.queryParams.subscribe(async (params) => {
|
this.route.queryParams.subscribe(async (params) => {
|
||||||
if (params.searchText) {
|
this.state = (await this.stateService.get<any>(ComponentId)) || {};
|
||||||
|
if (this.state.searchText) {
|
||||||
|
this.searchText = this.state.searchText;
|
||||||
|
} else if (params.searchText) {
|
||||||
this.searchText = params.searchText;
|
this.searchText = params.searchText;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.load();
|
this.load();
|
||||||
|
window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
this.saveState();
|
||||||
|
this.broadcasterService.unsubscribe(ComponentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
|
@ -137,26 +149,34 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
selectFolder(folder: FolderView) {
|
async selectFolder(folder: FolderView) {
|
||||||
super.selectFolder(folder);
|
super.selectFolder(folder);
|
||||||
this.router.navigate(['/ciphers'], { queryParams: { folderId: folder.id } });
|
this.router.navigate(['/ciphers'], { queryParams: { folderId: folder.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
selectCollection(collection: CollectionView) {
|
async selectCollection(collection: CollectionView) {
|
||||||
super.selectCollection(collection);
|
super.selectCollection(collection);
|
||||||
this.router.navigate(['/ciphers'], { queryParams: { collectionId: collection.id } });
|
this.router.navigate(['/ciphers'], { queryParams: { collectionId: collection.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
selectCipher(cipher: CipherView) {
|
async selectCipher(cipher: CipherView) {
|
||||||
this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } });
|
this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
addCipher() {
|
async addCipher() {
|
||||||
this.router.navigate(['/add-cipher']);
|
this.router.navigate(['/add-cipher']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async saveState() {
|
||||||
|
this.state = {
|
||||||
|
scrollY: this.popupUtils.getContentScrollY(window),
|
||||||
|
searchText: this.searchText,
|
||||||
|
};
|
||||||
|
await this.stateService.save(ComponentId, this.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue