mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
double click to launch cipher
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<a *ngFor="let c of ciphers" (click)="selectCipher(c)" href="#" appStopClick title="{{title}}"
|
<a *ngFor="let c of ciphers" (click)="selectCipher(c)" (dblclick)="doubleSelectCipher(c)"
|
||||||
|
href="#" appStopClick title="{{title}}"
|
||||||
class="box-content-row box-content-row-flex">
|
class="box-content-row box-content-row-flex">
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<app-vault-icon [cipher]="c"></app-vault-icon>
|
<app-vault-icon [cipher]="c"></app-vault-icon>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { PopupUtilsService } from '../services/popup-utils.service';
|
|||||||
})
|
})
|
||||||
export class CiphersListComponent {
|
export class CiphersListComponent {
|
||||||
@Output() onSelected = new EventEmitter<CipherView>();
|
@Output() onSelected = new EventEmitter<CipherView>();
|
||||||
|
@Output() onDoubleSelected = new EventEmitter<CipherView>();
|
||||||
@Output() onView = new EventEmitter<CipherView>();
|
@Output() onView = new EventEmitter<CipherView>();
|
||||||
@Input() ciphers: CipherView[];
|
@Input() ciphers: CipherView[];
|
||||||
@Input() showView = false;
|
@Input() showView = false;
|
||||||
@@ -38,6 +39,10 @@ export class CiphersListComponent {
|
|||||||
this.onSelected.emit(c);
|
this.onSelected.emit(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doubleSelectCipher(c: CipherView) {
|
||||||
|
this.onDoubleSelected.emit(c);
|
||||||
|
}
|
||||||
|
|
||||||
viewCipher(c: CipherView) {
|
viewCipher(c: CipherView) {
|
||||||
this.onView.emit(c);
|
this.onView.emit(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-ciphers-list [ciphers]="searchedCiphers" title="{{'viewItem' | i18n}}"
|
<app-ciphers-list [ciphers]="searchedCiphers" title="{{'viewItem' | i18n}}"
|
||||||
(onSelected)="selectCipher($event)"></app-ciphers-list>
|
(onSelected)="selectCipher($event)"
|
||||||
|
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Angulartics2 } from 'angulartics2';
|
||||||
|
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import {
|
import {
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
@@ -11,6 +13,8 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { BrowserApi } from '../../browser/browserApi';
|
||||||
|
|
||||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||||
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';
|
||||||
@@ -40,13 +44,16 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
|||||||
showAdd = true;
|
showAdd = true;
|
||||||
folderId: string = null;
|
folderId: string = null;
|
||||||
type: CipherType = null;
|
type: CipherType = null;
|
||||||
|
selectedTimeout: number;
|
||||||
|
preventSelected = false;
|
||||||
|
|
||||||
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 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) {
|
||||||
super(cipherService);
|
super(cipherService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,9 +134,30 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On
|
|||||||
}
|
}
|
||||||
|
|
||||||
selectCipher(cipher: CipherView) {
|
selectCipher(cipher: CipherView) {
|
||||||
|
this.selectedTimeout = window.setTimeout(() => {
|
||||||
|
if (!this.preventSelected) {
|
||||||
super.selectCipher(cipher);
|
super.selectCipher(cipher);
|
||||||
this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } });
|
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() {
|
addCipher() {
|
||||||
super.addCipher();
|
super.addCipher();
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-ciphers-list [ciphers]="favoriteCiphers" title="{{'viewItem' | i18n}}"
|
<app-ciphers-list [ciphers]="favoriteCiphers" title="{{'viewItem' | i18n}}"
|
||||||
(onSelected)="selectCipher($event)"></app-ciphers-list>
|
(onSelected)="selectCipher($event)"
|
||||||
|
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box list">
|
<div class="box list">
|
||||||
@@ -121,7 +122,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-ciphers-list [ciphers]="noFolderCiphers" title="{{'viewItem' | i18n}}"
|
<app-ciphers-list [ciphers]="noFolderCiphers" title="{{'viewItem' | i18n}}"
|
||||||
(onSelected)="selectCipher($event)"></app-ciphers-list>
|
(onSelected)="selectCipher($event)"
|
||||||
|
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -133,7 +135,8 @@
|
|||||||
<div class="box list full-list" *ngIf="searchedCiphers.length > 0">
|
<div class="box list full-list" *ngIf="searchedCiphers.length > 0">
|
||||||
<div class="box-content">
|
<div class="box-content">
|
||||||
<app-ciphers-list [ciphers]="searchedCiphers" title="{{'viewItem' | i18n}}"
|
<app-ciphers-list [ciphers]="searchedCiphers" title="{{'viewItem' | i18n}}"
|
||||||
(onSelected)="selectCipher($event)"></app-ciphers-list>
|
(onSelected)="selectCipher($event)"
|
||||||
|
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Angulartics2 } from 'angulartics2';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
@@ -10,6 +12,8 @@ import {
|
|||||||
Router,
|
Router,
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { BrowserApi } from '../../browser/browserApi';
|
||||||
|
|
||||||
import { CipherType } from 'jslib/enums/cipherType';
|
import { CipherType } from 'jslib/enums/cipherType';
|
||||||
|
|
||||||
import { CollectionView } from 'jslib/models/view/collectionView';
|
import { CollectionView } from 'jslib/models/view/collectionView';
|
||||||
@@ -46,13 +50,15 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
|||||||
searchText: string;
|
searchText: string;
|
||||||
state: any;
|
state: any;
|
||||||
loadedTimeout: number;
|
loadedTimeout: number;
|
||||||
|
selectedTimeout: number;
|
||||||
|
preventSelected = false;
|
||||||
|
|
||||||
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,
|
private stateService: StateService, private popupUtils: PopupUtilsService,
|
||||||
private syncService: SyncService) {
|
private syncService: SyncService, private analytics: Angulartics2) {
|
||||||
super(collectionService, folderService);
|
super(collectionService, folderService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +103,12 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
if (this.loadedTimeout != null) {
|
||||||
window.clearTimeout(this.loadedTimeout);
|
window.clearTimeout(this.loadedTimeout);
|
||||||
|
}
|
||||||
|
if (this.selectedTimeout != null) {
|
||||||
|
window.clearTimeout(this.selectedTimeout);
|
||||||
|
}
|
||||||
this.saveState();
|
this.saveState();
|
||||||
this.broadcasterService.unsubscribe(ComponentId);
|
this.broadcasterService.unsubscribe(ComponentId);
|
||||||
}
|
}
|
||||||
@@ -177,8 +188,29 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
|||||||
}
|
}
|
||||||
|
|
||||||
async selectCipher(cipher: CipherView) {
|
async selectCipher(cipher: CipherView) {
|
||||||
|
this.selectedTimeout = window.setTimeout(() => {
|
||||||
|
if (!this.preventSelected) {
|
||||||
this.router.navigate(['/view-cipher'], { queryParams: { cipherId: cipher.id } });
|
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() {
|
async addCipher() {
|
||||||
this.router.navigate(['/add-cipher']);
|
this.router.navigate(['/add-cipher']);
|
||||||
|
|||||||
Reference in New Issue
Block a user