mirror of
https://github.com/bitwarden/browser
synced 2025-12-22 19:23:52 +00:00
Merge branch 'master' into bugfix-attachments-in-popup
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
<div class="box" *ngIf="biometricLock">
|
||||
<div class="box-footer">
|
||||
<a class="btn primary block" (click)="unlockBiometric()">{{'unlockWithBiometrics' | i18n}}</a>
|
||||
<button class="btn primary block" (click)="unlockBiometric()" appStopClick>{{'unlockWithBiometrics' | i18n}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-center">
|
||||
|
||||
@@ -58,13 +58,12 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
||||
// ref: https://bugzilla.mozilla.org/show_bug.cgi?id=1562620
|
||||
this.initU2f = false;
|
||||
}
|
||||
const isSafari = this.platformUtilsService.isSafari();
|
||||
await super.ngOnInit();
|
||||
if (this.selectedProviderType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSafari && this.selectedProviderType === TwoFactorProviderType.Email &&
|
||||
if (this.selectedProviderType === TwoFactorProviderType.Email &&
|
||||
this.popupUtilsService.inPopup(window)) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('popup2faCloseMessage'),
|
||||
null, this.i18nService.t('yes'), this.i18nService.t('no'));
|
||||
|
||||
@@ -185,8 +185,6 @@ export const routerTransition = trigger('routerTransition', [
|
||||
|
||||
transition('tabs => premium', inSlideLeft),
|
||||
transition('premium => tabs', outSlideRight),
|
||||
]);
|
||||
|
||||
if (!BrowserApi.isSafariApi) {
|
||||
routerTransition.definitions.push(transition('tabs => lock', inSlideDown));
|
||||
}
|
||||
transition('tabs => lock', inSlideDown),
|
||||
]);
|
||||
|
||||
@@ -20,9 +20,14 @@ import { SetPasswordComponent } from './accounts/set-password.component';
|
||||
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
|
||||
import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||
import { SsoComponent } from './accounts/sso.component';
|
||||
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
||||
|
||||
import { PasswordGeneratorComponent } from './generator/password-generator.component';
|
||||
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
||||
|
||||
import { PrivateModeComponent } from './private-mode.component';
|
||||
import { TabsComponent } from './tabs.component';
|
||||
|
||||
import { ExcludedDomainsComponent } from './settings/excluded-domains.component';
|
||||
import { ExportComponent } from './settings/export.component';
|
||||
import { FolderAddEditComponent } from './settings/folder-add-edit.component';
|
||||
import { FoldersComponent } from './settings/folders.component';
|
||||
@@ -30,7 +35,7 @@ import { OptionsComponent } from './settings/options.component';
|
||||
import { PremiumComponent } from './settings/premium.component';
|
||||
import { SettingsComponent } from './settings/settings.component';
|
||||
import { SyncComponent } from './settings/sync.component';
|
||||
import { TabsComponent } from './tabs.component';
|
||||
|
||||
import { AddEditComponent } from './vault/add-edit.component';
|
||||
import { AttachmentsComponent } from './vault/attachments.component';
|
||||
import { CiphersComponent } from './vault/ciphers.component';
|
||||
@@ -41,6 +46,8 @@ import { PasswordHistoryComponent } from './vault/password-history.component';
|
||||
import { ShareComponent } from './vault/share.component';
|
||||
import { ViewComponent } from './vault/view.component';
|
||||
|
||||
import { SendComponent } from './send/send.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
@@ -200,6 +207,12 @@ const routes: Routes = [
|
||||
canActivate: [AuthGuardService],
|
||||
data: { state: 'sync' },
|
||||
},
|
||||
{
|
||||
path: 'excluded-domains',
|
||||
component: ExcludedDomainsComponent,
|
||||
canActivate: [AuthGuardService],
|
||||
data: { state: 'excluded-domains' },
|
||||
},
|
||||
{
|
||||
path: 'premium',
|
||||
component: PremiumComponent,
|
||||
@@ -258,6 +271,12 @@ const routes: Routes = [
|
||||
canActivate: [AuthGuardService],
|
||||
data: { state: 'tabs_settings' },
|
||||
},
|
||||
{
|
||||
path: 'send',
|
||||
component: SendComponent,
|
||||
canActivate: [AuthGuardService],
|
||||
data: { state: 'tabs_send' },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -25,10 +25,15 @@ import { SetPasswordComponent } from './accounts/set-password.component';
|
||||
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
|
||||
import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||
import { SsoComponent } from './accounts/sso.component';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
||||
import { PasswordGeneratorComponent } from './generator/password-generator.component';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { PrivateModeComponent } from './private-mode.component';
|
||||
import { TabsComponent } from './tabs.component';
|
||||
|
||||
import { ExcludedDomainsComponent } from './settings/excluded-domains.component';
|
||||
import { ExportComponent } from './settings/export.component';
|
||||
import { FolderAddEditComponent } from './settings/folder-add-edit.component';
|
||||
import { FoldersComponent } from './settings/folders.component';
|
||||
@@ -36,7 +41,7 @@ import { OptionsComponent } from './settings/options.component';
|
||||
import { PremiumComponent } from './settings/premium.component';
|
||||
import { SettingsComponent } from './settings/settings.component';
|
||||
import { SyncComponent } from './settings/sync.component';
|
||||
import { TabsComponent } from './tabs.component';
|
||||
|
||||
import { AddEditComponent } from './vault/add-edit.component';
|
||||
import { AttachmentsComponent } from './vault/attachments.component';
|
||||
import { CiphersComponent } from './vault/ciphers.component';
|
||||
@@ -47,6 +52,8 @@ import { PasswordHistoryComponent } from './vault/password-history.component';
|
||||
import { ShareComponent } from './vault/share.component';
|
||||
import { ViewComponent } from './vault/view.component';
|
||||
|
||||
import { SendComponent } from './send/send.component';
|
||||
|
||||
import { A11yTitleDirective } from 'jslib/angular/directives/a11y-title.directive';
|
||||
import { ApiActionDirective } from 'jslib/angular/directives/api-action.directive';
|
||||
import { AutofocusDirective } from 'jslib/angular/directives/autofocus.directive';
|
||||
@@ -181,6 +188,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
ColorPasswordPipe,
|
||||
CurrentTabComponent,
|
||||
EnvironmentComponent,
|
||||
ExcludedDomainsComponent,
|
||||
ExportComponent,
|
||||
FallbackSrcDirective,
|
||||
FolderAddEditComponent,
|
||||
@@ -203,6 +211,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
RegisterComponent,
|
||||
SearchCiphersPipe,
|
||||
SelectCopyDirective,
|
||||
SendComponent,
|
||||
SettingsComponent,
|
||||
ShareComponent,
|
||||
StopClickDirective,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<i class="fa fa-lg fa-list-alt" aria-hidden="true"></i>
|
||||
</span>
|
||||
<ng-container *ngIf="cipher.type === cipherType.Login">
|
||||
<span class="row-btn" appStopClick appStopProp appA11yTitle="{{'launch' | i18n}}" (click)="launch()"
|
||||
<span class="row-btn" appStopClick appStopProp appA11yTitle="{{'launch' | i18n}}" (click)="launchCipher()"
|
||||
*ngIf="!showView" [ngClass]="{disabled: !cipher.login.canLaunch}">
|
||||
<i class="fa fa-lg fa-share-square-o" aria-hidden="true"></i>
|
||||
</span>
|
||||
|
||||
@@ -29,6 +29,7 @@ import { PopupUtilsService } from '../services/popup-utils.service';
|
||||
})
|
||||
export class ActionButtonsComponent {
|
||||
@Output() onView = new EventEmitter<CipherView>();
|
||||
@Output() launchEvent = new EventEmitter<CipherView>();
|
||||
@Input() cipher: CipherView;
|
||||
@Input() showView = false;
|
||||
|
||||
@@ -44,16 +45,8 @@ export class ActionButtonsComponent {
|
||||
this.userHasPremiumAccess = await this.userService.canAccessPremium();
|
||||
}
|
||||
|
||||
launch() {
|
||||
if (this.cipher.type !== CipherType.Login || !this.cipher.login.canLaunch) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.analytics.eventTrack.next({ action: 'Launched URI From Listing' });
|
||||
BrowserApi.createNewTab(this.cipher.login.launchUri);
|
||||
if (this.popupUtilsService.inPopup(window)) {
|
||||
BrowserApi.closePopup(window);
|
||||
}
|
||||
launchCipher() {
|
||||
this.launchEvent.emit(this.cipher);
|
||||
}
|
||||
|
||||
async copy(cipher: CipherView, value: string, typeI18nKey: string, aType: string) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<a *ngFor="let c of ciphers" (click)="selectCipher(c)" (dblclick)="doubleSelectCipher(c)" href="#" appStopClick
|
||||
<a *ngFor="let c of ciphers" (click)="selectCipher(c)" (dblclick)="launchCipher(c)" href="#" appStopClick
|
||||
title="{{title}} - {{c.name}}" class="box-content-row box-content-row-flex">
|
||||
<div class="row-main">
|
||||
<app-vault-icon [cipher]="c"></app-vault-icon>
|
||||
@@ -17,6 +17,7 @@
|
||||
<span class="detail">{{c.subTitle}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<app-action-buttons [cipher]="c" [showView]="showView" (onView)="viewCipher(c)" class="action-buttons">
|
||||
<app-action-buttons [cipher]="c" [showView]="showView" (onView)="viewCipher(c)" (launchEvent)="launchCipher(c)"
|
||||
class="action-buttons">
|
||||
</app-action-buttons>
|
||||
</a>
|
||||
|
||||
@@ -15,7 +15,7 @@ import { CipherView } from 'jslib/models/view/cipherView';
|
||||
})
|
||||
export class CiphersListComponent {
|
||||
@Output() onSelected = new EventEmitter<CipherView>();
|
||||
@Output() onDoubleSelected = new EventEmitter<CipherView>();
|
||||
@Output() launchEvent = new EventEmitter<CipherView>();
|
||||
@Output() onView = new EventEmitter<CipherView>();
|
||||
@Input() ciphers: CipherView[];
|
||||
@Input() showView = false;
|
||||
@@ -27,8 +27,8 @@ export class CiphersListComponent {
|
||||
this.onSelected.emit(c);
|
||||
}
|
||||
|
||||
doubleSelectCipher(c: CipherView) {
|
||||
this.onDoubleSelected.emit(c);
|
||||
launchCipher(c: CipherView) {
|
||||
this.launchEvent.emit(c);
|
||||
}
|
||||
|
||||
viewCipher(c: CipherView) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<ng-container *ngIf="show">
|
||||
<ng-container>
|
||||
<button (click)="expand()" appA11yTitle="{{'popOutNewWindow' | i18n}}">
|
||||
<i class="fa fa-external-link fa-rotate-270 fa-lg fa-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@@ -22,8 +22,7 @@ export class PopOutComponent implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
if (this.show) {
|
||||
this.show = !this.platformUtilsService.isSafari();
|
||||
if (this.show && this.popupUtilsService.inSidebar(window) && this.platformUtilsService.isFirefox()) {
|
||||
if (this.popupUtilsService.inSidebar(window) && this.platformUtilsService.isFirefox()) {
|
||||
this.show = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,14 +281,13 @@ header {
|
||||
}
|
||||
|
||||
ul {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
width: 25%;
|
||||
float: left;
|
||||
flex: 1;
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@@ -329,12 +328,6 @@ header {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.tabs-3 {
|
||||
ul li {
|
||||
width: 33.33%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app-root {
|
||||
@@ -342,6 +335,9 @@ app-root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 980;
|
||||
@include themify($themes) {
|
||||
background-color: themed('backgroundColor');
|
||||
}
|
||||
}
|
||||
|
||||
content {
|
||||
|
||||
@@ -378,11 +378,13 @@
|
||||
&.disabled {
|
||||
@include themify($themes) {
|
||||
color: themed('disabledIconColor');
|
||||
opacity: themed('disabledBoxOpacity');
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include themify($themes) {
|
||||
color: themed('disabledIconColor');
|
||||
opacity: themed('disabledBoxOpacity');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
@import "variables.scss";
|
||||
|
||||
html.browser_safari {
|
||||
body {
|
||||
height: 360px !important;
|
||||
|
||||
&.body-xs {
|
||||
height: 300px !important;
|
||||
}
|
||||
|
||||
&.body-full {
|
||||
height: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
.search .fa {
|
||||
left: 20px;
|
||||
|
||||
@@ -9,7 +9,8 @@ $text-color: #000000;
|
||||
$border-color: #f0f0f0;
|
||||
$border-color-dark: #ddd;
|
||||
$list-item-hover: #fbfbfb;
|
||||
$list-icon-color: #c7c7cd;
|
||||
$list-icon-color: #767679;
|
||||
$disabled-box-opacity: 1;
|
||||
$border-radius: 3px;
|
||||
$line-height-base: 1.42857143;
|
||||
|
||||
@@ -59,6 +60,7 @@ $themes: (
|
||||
headerInputPlaceholderColor: lighten($brand-primary, 35%),
|
||||
listItemBackgroundHoverColor: $list-item-hover,
|
||||
disabledIconColor: $list-icon-color,
|
||||
disabledBoxOpacity: $disabled-box-opacity,
|
||||
headingColor: $gray-light,
|
||||
labelColor: $gray-light,
|
||||
mutedColor: $text-muted,
|
||||
@@ -106,7 +108,8 @@ $themes: (
|
||||
headerInputColor: #ffffff,
|
||||
headerInputPlaceholderColor: #707070,
|
||||
listItemBackgroundHoverColor: #3c3c3c,
|
||||
disabledIconColor: #c7c7cd,
|
||||
disabledIconColor: #cacaca,
|
||||
disabledBoxOpacity: 0.5,
|
||||
headingColor: #a3a3a3,
|
||||
labelColor: #a3a3a3,
|
||||
mutedColor: #a3a3a3,
|
||||
@@ -154,7 +157,8 @@ $themes: (
|
||||
headerInputColor: $nord2,
|
||||
headerInputPlaceholderColor: $nord3,
|
||||
listItemBackgroundHoverColor: $nord3,
|
||||
disabledIconColor: $nord5,
|
||||
disabledIconColor: $nord4,
|
||||
disabledBoxOpacity: 0.5,
|
||||
headingColor: $nord4,
|
||||
labelColor: $nord4,
|
||||
mutedColor: $nord4,
|
||||
|
||||
8
src/popup/send/send.component.html
Normal file
8
src/popup/send/send.component.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<header>
|
||||
</header>
|
||||
<content>
|
||||
<div class="no-items">
|
||||
<i class="fa fa-smile-o fa-4x"></i>
|
||||
<p>Coming soon...</p>
|
||||
</div>
|
||||
</content>
|
||||
35
src/popup/send/send.component.ts
Normal file
35
src/popup/send/send.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {
|
||||
Component,
|
||||
NgZone,
|
||||
} from '@angular/core';
|
||||
|
||||
import { SendView } from 'jslib/models/view/sendView';
|
||||
|
||||
import { SendComponent as BaseSendComponent } from 'jslib/angular/components/send/send.component';
|
||||
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SendService } from 'jslib/abstractions/send.service';
|
||||
|
||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-send',
|
||||
templateUrl: 'send.component.html',
|
||||
})
|
||||
export class SendComponent extends BaseSendComponent {
|
||||
constructor(sendService: SendService, i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService,
|
||||
broadcasterService: BroadcasterService, ngZone: NgZone) {
|
||||
super(sendService, i18nService, platformUtilsService, environmentService, broadcasterService, ngZone);
|
||||
}
|
||||
|
||||
addSend() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
editSend(send: SendView) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
@@ -71,8 +71,6 @@ export class PopupUtilsService {
|
||||
chrome.tabs.create({
|
||||
url: href,
|
||||
});
|
||||
} else if ((typeof safari !== 'undefined')) {
|
||||
// Safari can't open popup in full page tab :(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
src/popup/settings/excluded-domains.component.html
Normal file
53
src/popup/settings/excluded-domains.component.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<form #form (ngSubmit)="submit()">
|
||||
<header>
|
||||
<div class="left">
|
||||
<a routerLink="/tabs/settings">{{'cancel' | i18n}}</a>
|
||||
</div>
|
||||
<div class="center">
|
||||
<span class="title">{{'excludedDomains' | i18n}}</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button type="submit" appBlurClick>{{'save' | i18n}}</button>
|
||||
</div>
|
||||
</header>
|
||||
<content>
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<ng-container *ngIf="excludedDomains">
|
||||
<div class="box-content-row box-content-row-multi" appBoxRow
|
||||
*ngFor="let domain of excludedDomains; let i = index; trackBy:trackByFunction">
|
||||
<a href="#" appStopClick (click)="removeUri(i)" appA11yTitle="{{'remove' | i18n}}">
|
||||
<i class="fa fa-minus-circle fa-lg" aria-hidden="true"></i>
|
||||
</a>
|
||||
<div class="row-main">
|
||||
<label for="excludedDomain{{i}}">{{'uriPosition' | i18n : (i + 1)}}</label>
|
||||
<input id="excludedDomain{{i}}" name="excludedDomain{{i}}" type="text" [(ngModel)]="domain.uri"
|
||||
placeholder="{{'ex' | i18n}} https://google.com" inputmode="url" appInputVerbatim>
|
||||
<label for="currentUris{{i}}" class="sr-only">
|
||||
{{'currentUri' | i18n}} {{(i + 1)}}
|
||||
</label>
|
||||
<select *ngIf="currentUris && currentUris.length" id="currentUris{{i}}"
|
||||
name="currentUris{{i}}" [(ngModel)]="domain.uri" [hidden]="!domain.showCurrentUris">
|
||||
<option [ngValue]="null">-- {{'select' | i18n}} --</option>
|
||||
<option *ngFor="let u of currentUris" [ngValue]="u">{{u}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<a *ngIf="currentUris && currentUris.length" class="row-btn" href="#" appStopClick
|
||||
appBlurClick appA11yTitle="{{'toggleCurrentUris' | i18n}}" (click)="toggleUriInput(domain)">
|
||||
<i aria-hidden="true" class="fa fa-lg fa-list"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<a href="#" appStopClick appBlurClick (click)="addUri()"
|
||||
class="box-content-row box-content-row-newmulti">
|
||||
<i class="fa fa-plus-circle fa-fw fa-lg" aria-hidden="true"></i> {{'newUri' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
{{'excludedDomainsDesc' | i18n}}
|
||||
</div>
|
||||
</div>
|
||||
</content>
|
||||
</form>
|
||||
112
src/popup/settings/excluded-domains.component.ts
Normal file
112
src/popup/settings/excluded-domains.component.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
Component,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
NgZone
|
||||
} from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||
|
||||
import { BrowserApi } from '../../browser/browserApi';
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
interface ExcludedDomain {
|
||||
uri: string;
|
||||
showCurrentUris: boolean;
|
||||
}
|
||||
|
||||
const BroadcasterSubscriptionId = 'excludedDomains';
|
||||
|
||||
@Component({
|
||||
selector: 'app-excluded-domains',
|
||||
templateUrl: 'excluded-domains.component.html',
|
||||
})
|
||||
export class ExcludedDomainsComponent implements OnInit, OnDestroy {
|
||||
excludedDomains: ExcludedDomain[] = [];
|
||||
currentUris: string[];
|
||||
loadCurrentUrisTimeout: number;
|
||||
|
||||
constructor(private storageService: StorageService,
|
||||
private i18nService: I18nService, private router: Router,
|
||||
private broadcasterService: BroadcasterService, private ngZone: NgZone,
|
||||
private platformUtilsService: PlatformUtilsService) {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const savedDomains = await this.storageService.get<any>(ConstantsService.neverDomainsKey);
|
||||
if (savedDomains) {
|
||||
for (const uri of Object.keys(savedDomains)) {
|
||||
this.excludedDomains.push({ uri: uri, showCurrentUris: false });
|
||||
}
|
||||
}
|
||||
|
||||
await this.loadCurrentUris();
|
||||
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
this.ngZone.run(async () => {
|
||||
switch (message.command) {
|
||||
case 'tabChanged':
|
||||
case 'windowChanged':
|
||||
if (this.loadCurrentUrisTimeout != null) {
|
||||
window.clearTimeout(this.loadCurrentUrisTimeout);
|
||||
}
|
||||
this.loadCurrentUrisTimeout = window.setTimeout(async () => await this.loadCurrentUris(), 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
||||
}
|
||||
|
||||
async addUri() {
|
||||
this.excludedDomains.push({ uri: '', showCurrentUris: false });
|
||||
}
|
||||
|
||||
async removeUri(i: number) {
|
||||
this.excludedDomains.splice(i, 1);
|
||||
}
|
||||
|
||||
async submit() {
|
||||
const savedDomains: { [name: string]: null } = {};
|
||||
for (const domain of this.excludedDomains) {
|
||||
if (domain.uri && domain.uri !== '') {
|
||||
const validDomain = Utils.getHostname(domain.uri);
|
||||
if (!validDomain) {
|
||||
this.platformUtilsService.showToast('error', null,
|
||||
this.i18nService.t('excludedDomainsInvalidDomain', domain.uri));
|
||||
return;
|
||||
}
|
||||
savedDomains[validDomain] = null;
|
||||
}
|
||||
}
|
||||
await this.storageService.save(ConstantsService.neverDomainsKey, savedDomains);
|
||||
this.router.navigate(['/tabs/settings']);
|
||||
}
|
||||
|
||||
trackByFunction(index: number, item: any) {
|
||||
return index;
|
||||
}
|
||||
|
||||
toggleUriInput(domain: ExcludedDomain) {
|
||||
domain.showCurrentUris = !domain.showCurrentUris;
|
||||
}
|
||||
|
||||
async loadCurrentUris() {
|
||||
const tabs = await BrowserApi.tabsQuery({ windowType: 'normal' });
|
||||
if (tabs) {
|
||||
const uriSet = new Set(tabs.map((tab) => Utils.getHostname(tab.url)));
|
||||
uriSet.delete(null);
|
||||
this.currentUris = Array.from(uriSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
<div class="box-footer">{{'disableChangedPasswordNotificationDesc' | i18n}}</div>
|
||||
</div>
|
||||
<div class="box" *ngIf="showDisableContextMenu">
|
||||
<div class="box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<label for="context-menu">{{'disableContextMenuItem' | i18n}}</label>
|
||||
|
||||
@@ -29,7 +29,6 @@ export class OptionsComponent implements OnInit {
|
||||
disableChangedPasswordNotification = false;
|
||||
dontShowCards = false;
|
||||
dontShowIdentities = false;
|
||||
showDisableContextMenu = true;
|
||||
showClearClipboard = true;
|
||||
theme: string;
|
||||
themeOptions: any[];
|
||||
@@ -68,8 +67,6 @@ export class OptionsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.showDisableContextMenu = !this.platformUtilsService.isSafari();
|
||||
|
||||
this.enableAutoFillOnPageLoad = await this.storageService.get<boolean>(
|
||||
ConstantsService.enableAutoFillOnPageLoadKey);
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
<div class="row-main">{{'sync' | i18n}}</div>
|
||||
<i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i>
|
||||
</a>
|
||||
<a class="box-content-row box-content-row-flex text-default" routerLink="/excluded-domains">
|
||||
<div class="row-main">{{'excludedDomains' | i18n}}</div>
|
||||
<i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box list">
|
||||
@@ -42,7 +46,7 @@
|
||||
<label for="pin">{{'unlockWithPin' | i18n}}</label>
|
||||
<input id="pin" type="checkbox" (change)="updatePin()" [(ngModel)]="pin">
|
||||
</div>
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow *ngIf="supportsBiometric">
|
||||
<label for="biometric">{{'unlockWithBiometrics' | i18n}}</label>
|
||||
<input id="biometric" type="checkbox" (change)="updateBiometric()" [(ngModel)]="biometric">
|
||||
</div>
|
||||
|
||||
@@ -51,6 +51,7 @@ export class SettingsComponent implements OnInit {
|
||||
vaultTimeoutActions: any[];
|
||||
vaultTimeoutAction: string;
|
||||
pin: boolean = null;
|
||||
supportsBiometric: boolean;
|
||||
biometric: boolean = false;
|
||||
previousVaultTimeout: number = null;
|
||||
|
||||
@@ -101,6 +102,8 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
const pinSet = await this.vaultTimeoutService.isPinLockSet();
|
||||
this.pin = pinSet[0] || pinSet[1];
|
||||
|
||||
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
|
||||
this.biometric = await this.vaultTimeoutService.isBiometricLockSet();
|
||||
}
|
||||
|
||||
@@ -207,7 +210,33 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async updateBiometric() {
|
||||
if (this.biometric) {
|
||||
if (this.biometric && this.supportsBiometric) {
|
||||
|
||||
// Request permission to use the optional permission for nativeMessaging
|
||||
if (!this.platformUtilsService.isFirefox()) {
|
||||
const hasPermission = await new Promise((resolve) => {
|
||||
chrome.permissions.contains({permissions: ['nativeMessaging']}, resolve);
|
||||
});
|
||||
|
||||
if (!hasPermission) {
|
||||
await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('nativeMessagingPermissionPromptDesc'), this.i18nService.t('nativeMessagingPermissionPromptTitle'),
|
||||
this.i18nService.t('ok'), null);
|
||||
|
||||
const granted = await new Promise((resolve, reject) => {
|
||||
chrome.permissions.request({permissions: ['nativeMessaging']}, resolve);
|
||||
});
|
||||
|
||||
if (!granted) {
|
||||
await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('nativeMessaginPermissionErrorDesc'), this.i18nService.t('nativeMessaginPermissionErrorTitle'),
|
||||
this.i18nService.t('ok'), null);
|
||||
this.biometric = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const submitted = Swal.fire({
|
||||
heightAuto: false,
|
||||
buttonsStyling: false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="tab-page">
|
||||
<router-outlet></router-outlet>
|
||||
<nav class="tabs" [ngClass]="{'tabs-3': !showCurrentTab}">
|
||||
<nav class="tabs">
|
||||
<ul>
|
||||
<li routerLinkActive="active" *ngIf="showCurrentTab">
|
||||
<a routerLink="current" appA11yTitle="{{'currentTab' | i18n}}">
|
||||
@@ -12,6 +12,11 @@
|
||||
<i class="fa fa-lock fa-2x" aria-hidden="true"></i>{{'myVault' | i18n}}
|
||||
</a>
|
||||
</li>
|
||||
<li routerLinkActive="active">
|
||||
<a routerLink="send" appA11yTitle="{{'send' | i18n}}">
|
||||
<i class="fa fa-paper-plane fa-2x" aria-hidden="true"></i>{{'send' | i18n}}
|
||||
</a>
|
||||
</li>
|
||||
<li routerLinkActive="active">
|
||||
<a routerLink="generator" appA11yTitle="{{'passGen' | i18n}}">
|
||||
<i class="fa fa-refresh fa-2x" aria-hidden="true"></i>{{'generator' | i18n}}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<app-ciphers-list [ciphers]="filteredCiphers" title="{{'viewItem' | i18n}}"
|
||||
(onSelected)="selectCipher($event)" (onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||
(onSelected)="selectCipher($event)" (launchEvent)="launchCipher($event)"></app-ciphers-list>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<header>
|
||||
<div class="left" *ngIf="showLeftHeader">
|
||||
<div class="left">
|
||||
<app-pop-out [show]="!inSidebar"></app-pop-out>
|
||||
<button type="button" appBlurClick (click)="refresh()" appA11yTitle="{{'refresh' | i18n}}" *ngIf="inSidebar">
|
||||
<i class="fa fa-retweet fa-lg fa-fw" aria-hidden="true"></i>
|
||||
|
||||
@@ -49,7 +49,6 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
|
||||
hostname: string;
|
||||
searchText: string;
|
||||
inSidebar = false;
|
||||
showLeftHeader = false;
|
||||
searchTypeSearch = false;
|
||||
loaded = false;
|
||||
|
||||
@@ -68,7 +67,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.showLeftHeader = this.searchTypeSearch = !this.platformUtilsService.isSafari();
|
||||
this.searchTypeSearch = !this.platformUtilsService.isSafari();
|
||||
this.inSidebar = this.popupUtilsService.inSidebar(window);
|
||||
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<header>
|
||||
<div class="left" *ngIf="showLeftHeader">
|
||||
<div class="left">
|
||||
<app-pop-out></app-pop-out>
|
||||
</div>
|
||||
<div class="search">
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<app-ciphers-list [ciphers]="favoriteCiphers" title="{{'viewItem' | i18n}}"
|
||||
(onSelected)="selectCipher($event)" (onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||
(onSelected)="selectCipher($event)" (launchEvent)="launchCipher($event)"></app-ciphers-list>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box list">
|
||||
@@ -118,7 +118,7 @@
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<app-ciphers-list [ciphers]="noFolderCiphers" title="{{'viewItem' | i18n}}"
|
||||
(onSelected)="selectCipher($event)" (onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||
(onSelected)="selectCipher($event)" (launchEvent)="launchCipher($event)"></app-ciphers-list>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box list" *ngIf="deletedCount">
|
||||
@@ -146,7 +146,7 @@
|
||||
<div class="box list full-list" *ngIf="ciphers && ciphers.length > 0">
|
||||
<div class="box-content">
|
||||
<app-ciphers-list [ciphers]="ciphers" title="{{'viewItem' | i18n}}" (onSelected)="selectCipher($event)"
|
||||
(onDoubleSelected)="launchCipher($event)"></app-ciphers-list>
|
||||
(launchEvent)="launchCipher($event)"></app-ciphers-list>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -92,8 +92,7 @@ export class GroupingsComponent extends BaseGroupingsComponent implements OnInit
|
||||
|
||||
async ngOnInit() {
|
||||
this.searchTypeSearch = !this.platformUtilsService.isSafari();
|
||||
this.showLeftHeader = !this.platformUtilsService.isSafari() &&
|
||||
!(this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox());
|
||||
this.showLeftHeader = !(this.popupUtils.inSidebar(window) && this.platformUtilsService.isFirefox());
|
||||
this.stateService.remove('CiphersComponent');
|
||||
|
||||
this.broadcasterService.subscribe(ComponentId, (message: any) => {
|
||||
|
||||
Reference in New Issue
Block a user