diff --git a/src/popup/components/ciphers-list.component.html b/src/popup/components/ciphers-list.component.html index 8b2f8827e8c..4b188c1476a 100644 --- a/src/popup/components/ciphers-list.component.html +++ b/src/popup/components/ciphers-list.component.html @@ -1,4 +1,5 @@ -
diff --git a/src/popup/components/ciphers-list.component.ts b/src/popup/components/ciphers-list.component.ts index 0dfc0699c8d..b7c20492375 100644 --- a/src/popup/components/ciphers-list.component.ts +++ b/src/popup/components/ciphers-list.component.ts @@ -25,6 +25,7 @@ import { PopupUtilsService } from '../services/popup-utils.service'; }) export class CiphersListComponent { @Output() onSelected = new EventEmitter(); + @Output() onDoubleSelected = new EventEmitter(); @Output() onView = new EventEmitter(); @Input() ciphers: CipherView[]; @Input() showView = false; @@ -38,6 +39,10 @@ export class CiphersListComponent { this.onSelected.emit(c); } + doubleSelectCipher(c: CipherView) { + this.onDoubleSelected.emit(c); + } + viewCipher(c: CipherView) { this.onView.emit(c); } diff --git a/src/popup/vault/ciphers.component.html b/src/popup/vault/ciphers.component.html index d134d49518a..a71b5fe15cd 100644 --- a/src/popup/vault/ciphers.component.html +++ b/src/popup/vault/ciphers.component.html @@ -34,7 +34,8 @@
+ (onSelected)="selectCipher($event)" + (onDoubleSelected)="launchCipher($event)">
diff --git a/src/popup/vault/ciphers.component.ts b/src/popup/vault/ciphers.component.ts index 74b7f037a17..a9cc61fda8a 100644 --- a/src/popup/vault/ciphers.component.ts +++ b/src/popup/vault/ciphers.component.ts @@ -1,3 +1,5 @@ +import { Angulartics2 } from 'angulartics2'; + import { Location } from '@angular/common'; import { ChangeDetectorRef, @@ -11,6 +13,8 @@ import { Router, } from '@angular/router'; +import { BrowserApi } from '../../browser/browserApi'; + import { FolderService } from 'jslib/abstractions/folder.service'; import { CollectionService } from 'jslib/abstractions/collection.service'; import { CipherService } from 'jslib/abstractions/cipher.service'; @@ -40,13 +44,16 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On showAdd = true; folderId: string = null; type: CipherType = null; + selectedTimeout: number; + preventSelected = false; constructor(cipherService: CipherService, private route: ActivatedRoute, private router: Router, private location: Location, private ngZone: NgZone, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private stateService: StateService, private popupUtils: PopupUtilsService, private i18nService: I18nService, - private folderService: FolderService, private collectionService: CollectionService) { + private folderService: FolderService, private collectionService: CollectionService, + private analytics: Angulartics2) { super(cipherService); } @@ -127,8 +134,29 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On } selectCipher(cipher: CipherView) { - super.selectCipher(cipher); - this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } }); + this.selectedTimeout = window.setTimeout(() => { + if (!this.preventSelected) { + super.selectCipher(cipher); + this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } }); + } + this.preventSelected = false; + }, 200); + } + + async launchCipher(cipher: CipherView) { + if (cipher.type != CipherType.Login || !cipher.login.canLaunch) { + return; + } + + if (this.selectedTimeout != null) { + window.clearTimeout(this.selectedTimeout); + } + this.preventSelected = true; + this.analytics.eventTrack.next({ action: 'Launched URI From Listing' }); + BrowserApi.createNewTab(cipher.login.uri); + if (this.popupUtils.inPopup(window)) { + BrowserApi.closePopup(window); + } } addCipher() { diff --git a/src/popup/vault/groupings.component.html b/src/popup/vault/groupings.component.html index c811ef08414..15291099012 100644 --- a/src/popup/vault/groupings.component.html +++ b/src/popup/vault/groupings.component.html @@ -30,7 +30,8 @@
+ (onSelected)="selectCipher($event)" + (onDoubleSelected)="launchCipher($event)">
@@ -121,7 +122,8 @@
+ (onSelected)="selectCipher($event)" + (onDoubleSelected)="launchCipher($event)">
@@ -133,7 +135,8 @@
+ (onSelected)="selectCipher($event)" + (onDoubleSelected)="launchCipher($event)">
diff --git a/src/popup/vault/groupings.component.ts b/src/popup/vault/groupings.component.ts index 0c7694b8100..8e4cbe80169 100644 --- a/src/popup/vault/groupings.component.ts +++ b/src/popup/vault/groupings.component.ts @@ -1,3 +1,5 @@ +import { Angulartics2 } from 'angulartics2'; + import { ChangeDetectorRef, Component, @@ -10,6 +12,8 @@ import { Router, } from '@angular/router'; +import { BrowserApi } from '../../browser/browserApi'; + import { CipherType } from 'jslib/enums/cipherType'; import { CollectionView } from 'jslib/models/view/collectionView'; @@ -46,13 +50,15 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit searchText: string; state: any; loadedTimeout: number; + selectedTimeout: number; + preventSelected = false; constructor(collectionService: CollectionService, folderService: FolderService, private cipherService: CipherService, private router: Router, private ngZone: NgZone, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute, private stateService: StateService, private popupUtils: PopupUtilsService, - private syncService: SyncService) { + private syncService: SyncService, private analytics: Angulartics2) { super(collectionService, folderService); } @@ -85,7 +91,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit if (!this.syncService.syncInProgress) { this.load(); - window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0); + window.setTimeout(() => this.popupUtils.setContentScrollY(window, this.state.scrollY), 0); } else { this.loadedTimeout = window.setTimeout(async () => { if (!this.loaded) { @@ -97,7 +103,12 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit } ngOnDestroy() { - window.clearTimeout(this.loadedTimeout); + if (this.loadedTimeout != null) { + window.clearTimeout(this.loadedTimeout); + } + if (this.selectedTimeout != null) { + window.clearTimeout(this.selectedTimeout); + } this.saveState(); this.broadcasterService.unsubscribe(ComponentId); } @@ -177,7 +188,28 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit } async selectCipher(cipher: CipherView) { - this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } }); + this.selectedTimeout = window.setTimeout(() => { + if (!this.preventSelected) { + this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } }); + } + this.preventSelected = false; + }, 200); + } + + async launchCipher(cipher: CipherView) { + if (cipher.type != CipherType.Login || !cipher.login.canLaunch) { + return; + } + + if (this.selectedTimeout != null) { + window.clearTimeout(this.selectedTimeout); + } + this.preventSelected = true; + this.analytics.eventTrack.next({ action: 'Launched URI From Listing' }); + BrowserApi.createNewTab(cipher.login.uri); + if (this.popupUtils.inPopup(window)) { + BrowserApi.closePopup(window); + } } async addCipher() {