1
0
mirror of https://github.com/bitwarden/desktop.git synced 2024-11-30 12:54:31 +01:00

box row directive

This commit is contained in:
Kyle Spearrin 2018-01-30 14:33:06 -05:00
parent 654b4b42a0
commit 180e28fca3
4 changed files with 96 additions and 44 deletions

View File

@ -14,6 +14,7 @@ import { AddEditComponent } from './vault/add-edit.component';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { AttachmentsComponent } from './vault/attachments.component'; import { AttachmentsComponent } from './vault/attachments.component';
import { BlurClickDirective } from './directives/blur-click.directive'; import { BlurClickDirective } from './directives/blur-click.directive';
import { BoxRowDirective } from './directives/box-row.directive';
import { CiphersComponent } from './vault/ciphers.component'; import { CiphersComponent } from './vault/ciphers.component';
import { FallbackSrcDirective } from './directives/fallback-src.directive'; import { FallbackSrcDirective } from './directives/fallback-src.directive';
import { GroupingsComponent } from './vault/groupings.component'; import { GroupingsComponent } from './vault/groupings.component';
@ -46,6 +47,7 @@ import { ViewComponent } from './vault/view.component';
AppComponent, AppComponent,
AttachmentsComponent, AttachmentsComponent,
BlurClickDirective, BlurClickDirective,
BoxRowDirective,
CiphersComponent, CiphersComponent,
FallbackSrcDirective, FallbackSrcDirective,
GroupingsComponent, GroupingsComponent,

View File

@ -0,0 +1,49 @@
import {
Directive,
ElementRef,
HostListener,
OnInit,
} from '@angular/core';
@Directive({
selector: '[appBoxRow]',
})
export class BoxRowDirective implements OnInit {
el: HTMLElement = null;
formEls: NodeListOf<Element>;
constructor(private elRef: ElementRef) {
this.el = elRef.nativeElement;
}
ngOnInit(): void {
this.formEls = this.el.querySelectorAll('input:not([type="hidden"]), select, textarea');
this.formEls.forEach((formEl) => {
formEl.addEventListener('focus', (event: Event) => {
this.el.classList.add('active');
}, false);
formEl.addEventListener('blur', (event: Event) => {
this.el.classList.remove('active');
}, false);
});
}
@HostListener('click', ['$event']) onClick(event: Event) {
if (event.target !== this.el) {
return;
}
if (this.formEls.length > 0) {
const formEl = (this.formEls[0] as HTMLElement);
if (formEl.tagName.toLowerCase() === 'input') {
const inputEl = (formEl as HTMLInputElement);
if (inputEl.type != null && inputEl.type.toLowerCase() === 'checkbox') {
inputEl.checked = !inputEl.checked;
return;
}
}
formEl.focus();
}
}
}

View File

@ -5,28 +5,28 @@
{{'itemInformation' | i18n}} {{'itemInformation' | i18n}}
</div> </div>
<div class="box-content"> <div class="box-content">
<div class="box-content-row" *ngIf="!editMode"> <div class="box-content-row" *ngIf="!editMode" appBoxRow>
<label for="type">{{'type' | i18n}}</label> <label for="type">{{'type' | i18n}}</label>
<select id="type" name="Type" [(ngModel)]="cipher.type"> <select id="type" name="Type" [(ngModel)]="cipher.type">
<option *ngFor="let o of typeOptions" [ngValue]="o.value">{{o.name}}</option> <option *ngFor="let o of typeOptions" [ngValue]="o.value">{{o.name}}</option>
</select> </select>
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="name">{{'name' | i18n}}</label> <label for="name">{{'name' | i18n}}</label>
<input id="name" type="text" name="Name" [(ngModel)]="cipher.name"> <input id="name" type="text" name="Name" [(ngModel)]="cipher.name">
</div> </div>
<!-- Login --> <!-- Login -->
<div *ngIf="cipher.type === cipherType.Login"> <div *ngIf="cipher.type === cipherType.Login">
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="loginUri">{{'uri' | i18n}}</label> <label for="loginUri">{{'uri' | i18n}}</label>
<input id="loginUri" type="text" name="Login.Uri" [(ngModel)]="cipher.login.uri"> <input id="loginUri" type="text" name="Login.Uri" [(ngModel)]="cipher.login.uri">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="loginUsername">{{'username' | i18n}}</label> <label for="loginUsername">{{'username' | i18n}}</label>
<input id="loginUsername" type="text" name="Login.Username" <input id="loginUsername" type="text" name="Login.Username"
[(ngModel)]="cipher.login.username"> [(ngModel)]="cipher.login.username">
</div> </div>
<div class="box-content-row box-content-row-flex"> <div class="box-content-row box-content-row-flex" appBoxRow>
<div class="row-main"> <div class="row-main">
<label for="loginPassword">{{'password' | i18n}}</label> <label for="loginPassword">{{'password' | i18n}}</label>
<input id="loginPassword" class="monospaced" type="{{showPassword ? 'text' : 'password'}}" <input id="loginPassword" class="monospaced" type="{{showPassword ? 'text' : 'password'}}"
@ -47,121 +47,121 @@
</div> </div>
<!-- Card --> <!-- Card -->
<div *ngIf="cipher.type === cipherType.Card"> <div *ngIf="cipher.type === cipherType.Card">
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="cardCardholderName">{{'cardholderName' | i18n}}</label> <label for="cardCardholderName">{{'cardholderName' | i18n}}</label>
<input id="cardCardholderName" type="text" name="Card.CardCardholderName" <input id="cardCardholderName" type="text" name="Card.CardCardholderName"
[(ngModel)]="cipher.card.cardholderName"> [(ngModel)]="cipher.card.cardholderName">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="cardNumber">{{'number' | i18n}}</label> <label for="cardNumber">{{'number' | i18n}}</label>
<input id="cardNumber" type="text" name="Card.Number" [(ngModel)]="cipher.card.number"> <input id="cardNumber" type="text" name="Card.Number" [(ngModel)]="cipher.card.number">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="cardBrand">{{'brand' | i18n}}</label> <label for="cardBrand">{{'brand' | i18n}}</label>
<select id="cardBrand" name="Card.Brand" [(ngModel)]="cipher.card.brand"> <select id="cardBrand" name="Card.Brand" [(ngModel)]="cipher.card.brand">
<option *ngFor="let o of cardBrandOptions" [ngValue]="o.value">{{o.name}}</option> <option *ngFor="let o of cardBrandOptions" [ngValue]="o.value">{{o.name}}</option>
</select> </select>
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="cardExpMonth">{{'expirationMonth' | i18n}}</label> <label for="cardExpMonth">{{'expirationMonth' | i18n}}</label>
<select id="cardExpMonth" name="Card.ExpMonth" [(ngModel)]="cipher.card.expMonth"> <select id="cardExpMonth" name="Card.ExpMonth" [(ngModel)]="cipher.card.expMonth">
<option *ngFor="let o of cardExpMonthOptions" [ngValue]="o.value">{{o.name}}</option> <option *ngFor="let o of cardExpMonthOptions" [ngValue]="o.value">{{o.name}}</option>
</select> </select>
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="cardExpYear">{{'expirationYear' | i18n}}</label> <label for="cardExpYear">{{'expirationYear' | i18n}}</label>
<input id="cardExpYear" type="text" name="Card.ExpYear" [(ngModel)]="cipher.card.expYear" <input id="cardExpYear" type="text" name="Card.ExpYear" [(ngModel)]="cipher.card.expYear"
placeholder="{{'ex' | i18n}} 2019"> placeholder="{{'ex' | i18n}} 2019">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="cardCode">{{'securityCode' | i18n}}</label> <label for="cardCode">{{'securityCode' | i18n}}</label>
<input id="cardCode" type="text" name="Card.Code" [(ngModel)]="cipher.card.code"> <input id="cardCode" type="text" name="Card.Code" [(ngModel)]="cipher.card.code">
</div> </div>
</div> </div>
<!-- Identity --> <!-- Identity -->
<div *ngIf="cipher.type === cipherType.Identity"> <div *ngIf="cipher.type === cipherType.Identity">
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idTitle">{{'title' | i18n}}</label> <label for="idTitle">{{'title' | i18n}}</label>
<select id="idTitle" name="Identity.Title" [(ngModel)]="cipher.identity.title"> <select id="idTitle" name="Identity.Title" [(ngModel)]="cipher.identity.title">
<option *ngFor="let o of identityTitleOptions" [ngValue]="o.value">{{o.name}}</option> <option *ngFor="let o of identityTitleOptions" [ngValue]="o.value">{{o.name}}</option>
</select> </select>
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idFirstName">{{'firstName' | i18n}}</label> <label for="idFirstName">{{'firstName' | i18n}}</label>
<input id="idFirstName" type="text" name="Identity.FirstName" <input id="idFirstName" type="text" name="Identity.FirstName"
[(ngModel)]="cipher.identity.firstName"> [(ngModel)]="cipher.identity.firstName">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idMiddleName">{{'middleName' | i18n}}</label> <label for="idMiddleName">{{'middleName' | i18n}}</label>
<input id="idMiddleName" type="text" name="Identity.MiddleName" <input id="idMiddleName" type="text" name="Identity.MiddleName"
[(ngModel)]="cipher.identity.middleName"> [(ngModel)]="cipher.identity.middleName">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idLastName">{{'lastName' | i18n}}</label> <label for="idLastName">{{'lastName' | i18n}}</label>
<input id="idLastName" type="text" name="Identity.LastName" <input id="idLastName" type="text" name="Identity.LastName"
[(ngModel)]="cipher.identity.lastName"> [(ngModel)]="cipher.identity.lastName">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idUsername">{{'username' | i18n}}</label> <label for="idUsername">{{'username' | i18n}}</label>
<input id="idUsername" type="text" name="Identity.Username" <input id="idUsername" type="text" name="Identity.Username"
[(ngModel)]="cipher.identity.username"> [(ngModel)]="cipher.identity.username">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idCompany">{{'company' | i18n}}</label> <label for="idCompany">{{'company' | i18n}}</label>
<input id="idCompany" type="text" name="Identity.Company" <input id="idCompany" type="text" name="Identity.Company"
[(ngModel)]="cipher.identity.company"> [(ngModel)]="cipher.identity.company">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idSsn">{{'ssn' | i18n}}</label> <label for="idSsn">{{'ssn' | i18n}}</label>
<input id="idSsn" type="text" name="Identity.SSN" [(ngModel)]="cipher.identity.ssn"> <input id="idSsn" type="text" name="Identity.SSN" [(ngModel)]="cipher.identity.ssn">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idPassportNumber">{{'passportNumber' | i18n}}</label> <label for="idPassportNumber">{{'passportNumber' | i18n}}</label>
<input id="idPassportNumber" type="text" name="Identity.PassportNumber" <input id="idPassportNumber" type="text" name="Identity.PassportNumber"
[(ngModel)]="cipher.identity.passportNumber"> [(ngModel)]="cipher.identity.passportNumber">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idLicenseNumber">{{'licenseNumber' | i18n}}</label> <label for="idLicenseNumber">{{'licenseNumber' | i18n}}</label>
<input id="idLicenseNumber" type="text" name="Identity.LicenseNumber" <input id="idLicenseNumber" type="text" name="Identity.LicenseNumber"
[(ngModel)]="cipher.identity.licenseNumber"> [(ngModel)]="cipher.identity.licenseNumber">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idEmail">{{'email' | i18n}}</label> <label for="idEmail">{{'email' | i18n}}</label>
<input id="idEmail" type="text" name="Identity.Email" [(ngModel)]="cipher.identity.email"> <input id="idEmail" type="text" name="Identity.Email" [(ngModel)]="cipher.identity.email">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idPhone">{{'phone' | i18n}}</label> <label for="idPhone">{{'phone' | i18n}}</label>
<input id="idPhone" type="text" name="Identity.Phone" [(ngModel)]="cipher.identity.phone"> <input id="idPhone" type="text" name="Identity.Phone" [(ngModel)]="cipher.identity.phone">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idAddress1">{{'address1' | i18n}}</label> <label for="idAddress1">{{'address1' | i18n}}</label>
<input id="idAddress1" type="text" name="Identity.Address1" <input id="idAddress1" type="text" name="Identity.Address1"
[(ngModel)]="cipher.identity.address1"> [(ngModel)]="cipher.identity.address1">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idAddress2">{{'address2' | i18n}}</label> <label for="idAddress2">{{'address2' | i18n}}</label>
<input id="idAddress2" type="text" name="Identity.Address2" <input id="idAddress2" type="text" name="Identity.Address2"
[(ngModel)]="cipher.identity.address2"> [(ngModel)]="cipher.identity.address2">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idAddress3">{{'address3' | i18n}}</label> <label for="idAddress3">{{'address3' | i18n}}</label>
<input id="idAddress3" type="text" name="Identity.Address3" <input id="idAddress3" type="text" name="Identity.Address3"
[(ngModel)]="cipher.identity.address3"> [(ngModel)]="cipher.identity.address3">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idCity">{{'cityTown' | i18n}}</label> <label for="idCity">{{'cityTown' | i18n}}</label>
<input id="idCity" type="text" name="Identity.City" [(ngModel)]="cipher.identity.city"> <input id="idCity" type="text" name="Identity.City" [(ngModel)]="cipher.identity.city">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idState">{{'stateProvince' | i18n}}</label> <label for="idState">{{'stateProvince' | i18n}}</label>
<input id="idState" type="text" name="Identity.State" [(ngModel)]="cipher.identity.state"> <input id="idState" type="text" name="Identity.State" [(ngModel)]="cipher.identity.state">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idPostalCode">{{'zipPostalCode' | i18n}}</label> <label for="idPostalCode">{{'zipPostalCode' | i18n}}</label>
<input id="idPostalCode" type="text" name="Identity.PostalCode" <input id="idPostalCode" type="text" name="Identity.PostalCode"
[(ngModel)]="cipher.identity.postalCode"> [(ngModel)]="cipher.identity.postalCode">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="idCountry">{{'country' | i18n}}</label> <label for="idCountry">{{'country' | i18n}}</label>
<input id="idCountry" type="text" name="Identity.Country" <input id="idCountry" type="text" name="Identity.Country"
[(ngModel)]="cipher.identity.country"> [(ngModel)]="cipher.identity.country">
@ -171,18 +171,18 @@
</div> </div>
<div class="box"> <div class="box">
<div class="box-content"> <div class="box-content">
<div class="box-content-row" *ngIf="cipher.type === cipherType.Login"> <div class="box-content-row" *ngIf="cipher.type === cipherType.Login" appBoxRow>
<label for="loginTotp">{{'authenticatorKeyTotp' | i18n}}</label> <label for="loginTotp">{{'authenticatorKeyTotp' | i18n}}</label>
<input id="loginTotp" type="text" name="Login.Totp" class="monospaced" <input id="loginTotp" type="text" name="Login.Totp" class="monospaced"
[(ngModel)]="cipher.login.totp"> [(ngModel)]="cipher.login.totp">
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<label for="folder">{{'folder' | i18n}}</label> <label for="folder">{{'folder' | i18n}}</label>
<select id="folder" name="FolderId" [(ngModel)]="cipher.folderId"> <select id="folder" name="FolderId" [(ngModel)]="cipher.folderId">
<option *ngFor="let f of folders" [ngValue]="f.id">{{f.name}}</option> <option *ngFor="let f of folders" [ngValue]="f.id">{{f.name}}</option>
</select> </select>
</div> </div>
<div class="box-content-row box-content-row-checkbox"> <div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="favorite">{{'favorite' | i18n}}</label> <label for="favorite">{{'favorite' | i18n}}</label>
<input id="favorite" type="checkbox" name="Favorite" [(ngModel)]="cipher.favorite"> <input id="favorite" type="checkbox" name="Favorite" [(ngModel)]="cipher.favorite">
</div> </div>
@ -198,8 +198,8 @@
<label for="notes">{{'notes' | i18n}}</label> <label for="notes">{{'notes' | i18n}}</label>
</div> </div>
<div class="box-content"> <div class="box-content">
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<textarea id="notes" name="Notes" rows="10" [(ngModel)]="cipher.notes"></textarea> <textarea id="notes" name="Notes" rows="6" [(ngModel)]="cipher.notes"></textarea>
</div> </div>
</div> </div>
</div> </div>
@ -209,7 +209,8 @@
</div> </div>
<div class="box-content"> <div class="box-content">
<div *ngIf="cipher.hasFields"> <div *ngIf="cipher.hasFields">
<div class="box-content-row box-content-row-cf" *ngFor="let f of cipher.fields; let i = index" <div class="box-content-row box-content-row-cf" appBoxRow
*ngFor="let f of cipher.fields; let i = index"
[ngClass]="{'box-content-row-checkbox': f.type === fieldType.Boolean}"> [ngClass]="{'box-content-row-checkbox': f.type === fieldType.Boolean}">
<a href="#" appStopClick (click)="removeField(f)" title="{{'remove' | i18n}}"> <a href="#" appStopClick (click)="removeField(f)" title="{{'remove' | i18n}}">
<i class="fa fa-close fa-lg"></i> <i class="fa fa-close fa-lg"></i>
@ -236,7 +237,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="box-content-row"> <div class="box-content-row" appBoxRow>
<a href="#" appStopClick (click)="addField()"> <a href="#" appStopClick (click)="addField()">
<i class="fa fa-plus-circle fa-fw fa-lg"></i> {{'newCustomField' | i18n}} <i class="fa fa-plus-circle fa-fw fa-lg"></i> {{'newCustomField' | i18n}}
</a> </a>

View File

@ -20,27 +20,27 @@
Options Options
</div> </div>
<div class="box-content condensed"> <div class="box-content condensed">
<div class="box-content-row box-content-row-slider"> <div class="box-content-row box-content-row-slider" appBoxRow>
<label for="length">{{'length' | i18n}}</label> <label for="length">{{'length' | i18n}}</label>
<span>{{options.length}}</span> <span>{{options.length}}</span>
<input id="length" type="range" min="5" max="128" step="1" [(ngModel)]="options.length"> <input id="length" type="range" min="5" max="128" step="1" [(ngModel)]="options.length">
</div> </div>
<div class="box-content-row box-content-row-checkbox"> <div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="uppercase">A-Z</label> <label for="uppercase">A-Z</label>
<input id="uppercase" type="checkbox" (change)="saveOptions()" <input id="uppercase" type="checkbox" (change)="saveOptions()"
[(ngModel)]="options.uppercase"> [(ngModel)]="options.uppercase">
</div> </div>
<div class="box-content-row box-content-row-checkbox"> <div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="lowercase">a-z</label> <label for="lowercase">a-z</label>
<input id="lowercase" type="checkbox" (change)="saveOptions()" <input id="lowercase" type="checkbox" (change)="saveOptions()"
[(ngModel)]="options.lowercase"> [(ngModel)]="options.lowercase">
</div> </div>
<div class="box-content-row box-content-row-checkbox"> <div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="numbers">0-9</label> <label for="numbers">0-9</label>
<input id="numbers" type="checkbox" (change)="saveOptions()" <input id="numbers" type="checkbox" (change)="saveOptions()"
[(ngModel)]="options.number"> [(ngModel)]="options.number">
</div> </div>
<div class="box-content-row box-content-row-checkbox"> <div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="special">!@#$%^&*</label> <label for="special">!@#$%^&*</label>
<input id="special" type="checkbox" (change)="saveOptions()" <input id="special" type="checkbox" (change)="saveOptions()"
[(ngModel)]="options.special"> [(ngModel)]="options.special">
@ -49,17 +49,17 @@
</div> </div>
<div class="box"> <div class="box">
<div class="box-content condensed"> <div class="box-content condensed">
<div class="box-content-row box-content-row-input"> <div class="box-content-row box-content-row-input" appBoxRow>
<label for="min-number">{{'minNumbers' | i18n}}</label> <label for="min-number">{{'minNumbers' | i18n}}</label>
<input id="min-number" type="number" min="0" max="5" (change)="saveOptions()" <input id="min-number" type="number" min="0" max="5" (change)="saveOptions()"
[(ngModel)]="options.minNumber"> [(ngModel)]="options.minNumber">
</div> </div>
<div class="box-content-row box-content-row-input"> <div class="box-content-row box-content-row-input" appBoxRow>
<label for="min-special">{{'minSpecial' | i18n}}</label> <label for="min-special">{{'minSpecial' | i18n}}</label>
<input id="min-special" type="number" min="0" max="5" (change)="saveOptions()" <input id="min-special" type="number" min="0" max="5" (change)="saveOptions()"
[(ngModel)]="options.minSpecial"> [(ngModel)]="options.minSpecial">
</div> </div>
<div class="box-content-row box-content-row-checkbox"> <div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="ambiguous">{{'ambiguous' | i18n}}</label> <label for="ambiguous">{{'ambiguous' | i18n}}</label>
<input id="ambiguous" type="checkbox" (change)="saveOptions()" <input id="ambiguous" type="checkbox" (change)="saveOptions()"
[(ngModel)]="options.ambiguous"> [(ngModel)]="options.ambiguous">