manage state for vault pages

This commit is contained in:
Kyle Spearrin 2018-04-09 14:17:58 -04:00
parent 9d737f76d1
commit a3fc1c8d30
5 changed files with 83 additions and 26 deletions

View File

@ -9,6 +9,7 @@ import {
OnInit,
} from '@angular/core';
import {
NavigationEnd,
Router,
RouterOutlet,
} from '@angular/router';
@ -22,6 +23,7 @@ import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
import { AuthService } from 'jslib/abstractions/auth.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { StateService } from 'jslib/abstractions/state.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { ConstantsService } from 'jslib/services/constants.service';
@ -49,11 +51,13 @@ export class AppComponent implements OnInit {
});
private lastActivity: number = null;
private previousUrl: string = '';
constructor(private angulartics2GoogleAnalytics: Angulartics2GoogleAnalytics, private analytics: Angulartics2,
private toasterService: ToasterService, private storageService: StorageService,
private broadcasterService: BroadcasterService, private authService: AuthService,
private i18nService: I18nService, private router: Router) { }
private i18nService: I18nService, private router: Router,
private stateService: StateService) { }
ngOnInit() {
window.onmousemove = () => this.recordActivity();
@ -80,6 +84,17 @@ export class AppComponent implements OnInit {
};
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) {

View File

@ -18,4 +18,16 @@ export class PopupUtilsService {
return win.location.search === '' || win.location.search.indexOf('uilocation=') === -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;
}
}
}

View File

@ -1,14 +1,4 @@
import {
Component,
ComponentFactoryResolver,
NgZone,
OnDestroy,
OnInit,
Type,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { Router } from '@angular/router';
import { Component } from '@angular/core';
@Component({
selector: 'app-tabs',

View File

@ -12,6 +12,7 @@ import {
} from '@angular/router';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { StateService } from 'jslib/abstractions/state.service';
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';
const BroadcasterSubscriptionId = 'CiphersComponent';
import { PopupUtilsService } from '../services/popup-utils.service';
const ComponentId = 'CiphersComponent';
@Component({
selector: 'app-vault-ciphers',
@ -27,11 +30,13 @@ const BroadcasterSubscriptionId = 'CiphersComponent';
})
export class CiphersComponent extends BaseCiphersComponent implements OnInit, OnDestroy {
searchText: string;
state: any;
constructor(cipherService: CipherService, private route: ActivatedRoute,
private router: Router, private location: Location,
private ngZone: NgZone, private broadcasterService: BroadcasterService,
private changeDetectorRef: ChangeDetectorRef) {
private changeDetectorRef: ChangeDetectorRef, private stateService: StateService,
private popupUtils: PopupUtilsService) {
super(cipherService);
}
@ -47,9 +52,15 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
} else {
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 () => {
switch (message.command) {
case 'syncCompleted':
@ -67,7 +78,8 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
}
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
this.saveState();
this.broadcasterService.unsubscribe(ComponentId);
}
selectCipher(cipher: CipherView) {
@ -83,4 +95,12 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
back() {
this.location.back();
}
private async saveState() {
this.state = {
scrollY: this.popupUtils.getContentScrollY(window),
searchText: this.searchText,
};
await this.stateService.save(ComponentId, this.state);
}
}

View File

@ -19,12 +19,15 @@ import { FolderView } from 'jslib/models/view/folderView';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { StateService } from 'jslib/abstractions/state.service';
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
import { GroupingsComponent as BaseGroupingsComponent } from 'jslib/angular/components/groupings.component';
const BroadcasterSubscriptionId = 'GroupingsComponent';
import { PopupUtilsService } from '../services/popup-utils.service';
const ComponentId = 'GroupingsComponent';
@Component({
selector: 'app-vault-groupings',
@ -40,16 +43,20 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
typeCounts = new Map<CipherType, number>();
showNoFolderCiphers = false;
searchText: string;
state: any;
constructor(collectionService: CollectionService, folderService: FolderService,
private cipherService: CipherService, private router: Router,
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);
}
ngOnInit() {
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
this.stateService.remove('CiphersComponent');
this.broadcasterService.subscribe(ComponentId, (message: any) => {
this.ngZone.run(async () => {
switch (message.command) {
case 'syncCompleted':
@ -66,16 +73,21 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
});
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.load();
window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0);
});
}
ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
this.saveState();
this.broadcasterService.unsubscribe(ComponentId);
}
async load() {
@ -137,26 +149,34 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
});
}
selectType(type: CipherType) {
async selectType(type: CipherType) {
super.selectType(type);
this.router.navigate(['/ciphers'], { queryParams: { type: type } });
}
selectFolder(folder: FolderView) {
async selectFolder(folder: FolderView) {
super.selectFolder(folder);
this.router.navigate(['/ciphers'], { queryParams: { folderId: folder.id } });
}
selectCollection(collection: CollectionView) {
async selectCollection(collection: CollectionView) {
super.selectCollection(collection);
this.router.navigate(['/ciphers'], { queryParams: { collectionId: collection.id } });
}
selectCipher(cipher: CipherView) {
async selectCipher(cipher: CipherView) {
this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } });
}
addCipher() {
async addCipher() {
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);
}
}