some i18n and modal work

This commit is contained in:
Kyle Spearrin 2018-06-07 09:05:25 -04:00
parent a0ace6e70f
commit 08dc36fbb0
8 changed files with 598 additions and 282 deletions

View File

@ -1,5 +1,318 @@
{
"hello": {
"message": "hello world"
"whatTypeOfItem": {
"message": "What type of item is this?"
},
"name": {
"message": "Name"
},
"uri": {
"message": "URI"
},
"uriPosition": {
"message": "URI $POSITION$",
"description": "A listing of URIs. Ex: URI 1, URI 2, URI 3, etc.",
"placeholders": {
"position": {
"content": "$1",
"example": "2"
}
}
},
"newUri": {
"message": "New URI"
},
"username": {
"message": "Username"
},
"password": {
"message": "Password"
},
"notes": {
"message": "Notes"
},
"customFields": {
"message": "Custom Fields"
},
"cardholderName": {
"message": "Cardholder Name"
},
"number": {
"message": "Number"
},
"brand": {
"message": "Brand"
},
"expiration": {
"message": "Expiration"
},
"securityCode": {
"message": "Security Code"
},
"identityName": {
"message": "Identity Name"
},
"company": {
"message": "Company"
},
"ssn": {
"message": "Social Security Number"
},
"passportNumber": {
"message": "Passport Number"
},
"licenseNumber": {
"message": "License Number"
},
"email": {
"message": "Email"
},
"phone": {
"message": "Phone"
},
"january": {
"message": "January"
},
"february": {
"message": "February"
},
"march": {
"message": "March"
},
"april": {
"message": "April"
},
"may": {
"message": "May"
},
"june": {
"message": "June"
},
"july": {
"message": "July"
},
"august": {
"message": "August"
},
"september": {
"message": "September"
},
"october": {
"message": "October"
},
"november": {
"message": "November"
},
"december": {
"message": "December"
},
"title": {
"message": "Title"
},
"mr": {
"message": "Mr"
},
"mrs": {
"message": "Mrs"
},
"ms": {
"message": "Ms"
},
"dr": {
"message": "Dr"
},
"expirationMonth": {
"message": "Expiration Month"
},
"expirationYear": {
"message": "Expiration Year"
},
"authenticatorKeyTotp": {
"message": "Authenticator Key (TOTP)"
},
"folder": {
"message": "Folder"
},
"newCustomField": {
"message": "New Custom Field"
},
"value": {
"message": "Value"
},
"cfTypeText": {
"message": "Text"
},
"cfTypeHidden": {
"message": "Hidden"
},
"cfTypeBoolean": {
"message": "Boolean"
},
"remove": {
"message": "Remove"
},
"noneFolder": {
"message": "No Folder",
"description": "This is the folder for uncategorized items"
},
"addFolder": {
"message": "Add Folder"
},
"editFolder": {
"message": "Edit Folder"
},
"baseDomain": {
"message": "Base domain"
},
"host": {
"message": "Host",
"description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'."
},
"exact": {
"message": "Exact"
},
"startsWith": {
"message": "Starts with"
},
"regEx": {
"message": "Regular expression",
"description": "A programming term, also known as 'RegEx'."
},
"matchDetection": {
"message": "Match Detection",
"description": "URI match detection for auto-fill."
},
"defaultMatchDetection": {
"message": "Default match detection",
"description": "Default URI match detection for auto-fill."
},
"never": {
"message": "Never"
},
"toggleVisibility": {
"message": "Toggle Visibility"
},
"generatePassword": {
"message": "Generate Password"
},
"checkPassword": {
"message": "Check if password has been exposed."
},
"passwordExposed": {
"message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.",
"placeholders": {
"value": {
"content": "$1",
"example": "2"
}
}
},
"passwordSafe": {
"message": "This password was not found in any known data breaches. It should be safe to use."
},
"save": {
"message": "Save"
},
"cancel": {
"message": "Cancel"
},
"close": {
"message": "Close"
},
"delete": {
"message": "Delete"
},
"favorite": {
"message": "Favorite"
},
"edit": {
"message": "Edit"
},
"searchCollection": {
"message": "Search Collection"
},
"searchFolder": {
"message": "Search Folder"
},
"searchFavorites": {
"message": "Search Favorites"
},
"searchType": {
"message": "Search Type",
"description": "Search item type"
},
"searchVault": {
"message": "Search Vault"
},
"allItems": {
"message": "All Items"
},
"favorites": {
"message": "Favorites"
},
"types": {
"message": "Types"
},
"typeLogin": {
"message": "Login"
},
"typeCard": {
"message": "Card"
},
"typeIdentity": {
"message": "Identity"
},
"typeSecureNote": {
"message": "Secure Note"
},
"folders": {
"message": "Folders"
},
"collections": {
"message": "Collections"
},
"firstName": {
"message": "First Name"
},
"middleName": {
"message": "Middle Name"
},
"lastName": {
"message": "Last Name"
},
"address1": {
"message": "Address 1"
},
"address2": {
"message": "Address 2"
},
"address3": {
"message": "Address 3"
},
"cityTown": {
"message": "City / Town"
},
"stateProvince": {
"message": "State / Province"
},
"zipPostalCode": {
"message": "Zip / Postal Code"
},
"country": {
"message": "Country"
},
"shared": {
"message": "Shared"
},
"attachments": {
"message": "Attachments"
},
"select": {
"message": "Select"
},
"addItem": {
"message": "Add Item"
},
"editItem": {
"message": "Edit Item"
}
}

View File

@ -1,24 +1,28 @@
<div class="modal fade">
<div class="modal-dialog modal-lg">
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="modal-header">{{title}}</div>
<div class="modal-body">
<div class="content">
<div class="inner-content" *ngIf="cipher">
<div class="box">
<div class="box-header">
{{title}}
</div>
<div class="box-content">
<div class="box-content-row" *ngIf="!editMode" appBoxRow>
<label for="type">{{'type' | i18n}}</label>
<div class="row" *ngIf="!editMode">
<div class="col-6">
<div class="form-group">
<label for="type">{{'whatTypeOfItem' | i18n}}</label>
<select id="type" name="Type" [(ngModel)]="cipher.type">
<option *ngFor="let o of typeOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row" appBoxRow>
<label for="name">{{'name' | i18n}}</label>
<input id="name" type="text" name="Name" [(ngModel)]="cipher.name" [appAutofocus]="!editMode">
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-group">
<label for="name">{{'name' | i18n}}</label>
<input id="name" class="form-control" type="text" name="Name" [(ngModel)]="cipher.name" [appAutofocus]="!editMode">
</div>
</div>
</div>
<div class="box">
<div class="box-content">
<!-- Login -->
<div *ngIf="cipher.type === cipherType.Login">
<div class="box-content-row" appBoxRow>
@ -256,8 +260,7 @@
</div>
</div>
</div>
</div>
<div class="footer">
<div class="modal-footer">
<button appBlurClick type="submit" class="primary" title="{{'save' | i18n}}" [disabled]="form.loading">
<i class="fa fa-save fa-lg fa-fw" [hidden]="form.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!form.loading"></i>
@ -273,7 +276,6 @@
</button>
</div>
</div>
</div>
</form>
</div>
</div>

View File

@ -9,7 +9,7 @@
<app-vault-icon [cipher]="c"></app-vault-icon>
</td>
<td>
<a href="#" appStopClick (click)="selectCipher(c)" title="{{'viewItem' | i18n}}">{{c.name}}</a>
<a href="#" appStopClick (click)="selectCipher(c)" title="{{'editItem' | i18n}}">{{c.name}}</a>
<i class="fa fa-share-alt text-muted" *ngIf="c.organizationId" title="{{'shared' | i18n}}"></i>
<i class="fa fa-paperclip text-muted" *ngIf="c.hasAttachments" title="{{'attachments' | i18n}}"></i>
<small>{{c.subTitle}}</small>

View File

@ -20,7 +20,7 @@
<i class="fa fa-save fa-lg fa-fw" [hidden]="form.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!form.loading"></i>
</button>
<button type="button" data-dismiss="modal">{{'close' | i18n}}</button>
<button type="button" data-dismiss="modal" title="{{'cancel' | i18n}}">{{'cancel' | i18n}}</button>
<div class="right">
<button #deleteBtn appBlurClick type="button" (click)="delete()" class="danger"
title="{{'delete' | i18n}}" *ngIf="editMode" [disabled]="deleteBtn.loading"

View File

@ -3,47 +3,47 @@
Filters
</div>
<div class="card-body">
<input type="search" placeholder="{{searchPlaceholder || ('searchVault' | i18n)}}" id="search"
class="form-control" [(ngModel)]="searchText" (input)="searchTextChanged()" appAutofocus>
<input type="search" placeholder="{{searchPlaceholder || ('searchVault' | i18n)}}" id="search" class="form-control" [(ngModel)]="searchText"
(input)="searchTextChanged()" appAutofocus>
<ul class="fa-ul">
<li [ngClass]="{active: selectedAll}">
<a href="#" appStopClick appBlurClick (click)="selectAll()">
<i class="fa-li fa fa-fw fa-th"></i>All Items
<i class="fa-li fa fa-fw fa-th"></i>{{'allItems' | i18n}}
</a>
</li>
<li [ngClass]="{active: selectedFavorites}">
<a href="#" appStopClick appBlurClick (click)="selectFavorites()">
<i class="fa-li fa fa-fw fa-star"></i>Favorites
<i class="fa-li fa fa-fw fa-star"></i>{{'favorites' | i18n}}
</a>
</li>
</ul>
<h3>Types</h3>
<h3>{{'types' | i18n}}</h3>
<ul class="fa-ul">
<li [ngClass]="{active: selectedType === cipherType.Login}">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Login)">
<i class="fa-li fa fa-fw fa-globe"></i>Login
<i class="fa-li fa fa-fw fa-globe"></i>{{'typeLogin' | i18n}}
</a>
</li>
<li [ngClass]="{active: selectedType === cipherType.Card}">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Card)">
<i class="fa-li fa fa-fw fa-credit-card"></i>Card
<i class="fa-li fa fa-fw fa-credit-card"></i>{{'typeCard' | i18n}}
</a>
</li>
<li [ngClass]="{active: selectedType === cipherType.Identity}">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Identity)">
<i class="fa-li fa fa-fw fa-id-card-o"></i>Identity
<i class="fa-li fa fa-fw fa-id-card-o"></i>{{'typeIdentity' | i18n}}
</a>
</li>
<li [ngClass]="{active: selectedType === cipherType.SecureNote}">
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.SecureNote)">
<i class="fa-li fa fa-fw fa-sticky-note-o"></i>Secure Note
<i class="fa-li fa fa-fw fa-sticky-note-o"></i>{{'typeSecureNote' | i18n}}
</a>
</li>
</ul>
<p *ngIf="!loaded" class="text-muted">Loading...</p>
<p *ngIf="!loaded" class="text-muted"><i class="fa fa-spinner fa-spin"></i></p>
<ng-container *ngIf="loaded">
<h3>
Folders
{{'folders' | i18n}}
<button appBlurClick (click)="addFolder()" title="{{'addFolder' | i18n}}">
<i class="fa fa-plus fa-fw"></i>
</button>
@ -59,7 +59,7 @@
</li>
</ul>
<div *ngIf="collections && collections.length">
<h3>Collections</h3>
<h3>{{'collections' | i18n}}</h3>
<ul class="fa-ul">
<li *ngFor="let c of collections" [ngClass]="{active: c.id === selectedCollectionId}">
<a href="#" appStopClick appBlurClick (click)="selectCollection(c)">

View File

@ -16,6 +16,7 @@ import { GroupingsComponent as BaseGroupingsComponent } from 'jslib/angular/comp
export class GroupingsComponent extends BaseGroupingsComponent {
@Output() onSearchTextChanged = new EventEmitter<string>();
searchText: string = '';
searchPlaceholder: string = null;
constructor(collectionService: CollectionService, folderService: FolderService) {
super(collectionService, folderService);

View File

@ -55,7 +55,7 @@
<div class="container footer text-muted">
<div class="row">
<div class="col">
&copy; 2015-2018 8bit Solutions LLC
&copy; 2018, 8bit Solutions LLC
</div>
<div class="col text-center">

View File

@ -83,14 +83,14 @@ export class VaultComponent implements OnInit {
}
async clearGroupingFilters() {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchVault');
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchVault');
await this.ciphersComponent.load();
this.clearFilters();
this.go();
}
async filterFavorites() {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchFavorites');
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchFavorites');
await this.ciphersComponent.load((c) => c.favorite);
this.clearFilters();
this.favorites = true;
@ -98,7 +98,7 @@ export class VaultComponent implements OnInit {
}
async filterCipherType(type: CipherType) {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchType');
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchType');
await this.ciphersComponent.load((c) => c.type === type);
this.clearFilters();
this.type = type;
@ -107,7 +107,7 @@ export class VaultComponent implements OnInit {
async filterFolder(folderId: string) {
folderId = folderId === 'none' ? null : folderId;
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchFolder');
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchFolder');
await this.ciphersComponent.load((c) => c.folderId === folderId);
this.clearFilters();
this.folderId = folderId == null ? 'none' : folderId;
@ -115,7 +115,7 @@ export class VaultComponent implements OnInit {
}
async filterCollection(collectionId: string) {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchCollection');
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchCollection');
await this.ciphersComponent.load((c) => c.collectionIds.indexOf(collectionId) > -1);
this.clearFilters();
this.collectionId = collectionId;