You've already forked openaccounting-web
mirror of
https://github.com/openaccounting/oa-web.git
synced 2025-12-09 09:01:24 +13:00
replace tx blur with click handler
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<div class="autocomplete" [ngClass]="{visible: visible}" (mousedown)="preventBlur()">
|
<div class="autocomplete" [ngClass]="{visible: visible}">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<div class="suggestion" *ngFor="let tx of txs$ | async">
|
<div class="suggestion" *ngFor="let tx of txs$ | async">
|
||||||
<a (click)="click(tx)">{{tx.description}}</a>
|
<a (click)="click(tx)">{{tx.description}}</a>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export class Autocomplete {
|
|||||||
@Input() item: TxItem;
|
@Input() item: TxItem;
|
||||||
@Input() accountId: string;
|
@Input() accountId: string;
|
||||||
@Output() tx = new EventEmitter<Transaction>();
|
@Output() tx = new EventEmitter<Transaction>();
|
||||||
@Output() interact = new EventEmitter<any>();
|
|
||||||
public visible: boolean;
|
public visible: boolean;
|
||||||
public txs$: Observable<Transaction[]>;
|
public txs$: Observable<Transaction[]>;
|
||||||
|
|
||||||
@@ -65,11 +64,4 @@ export class Autocomplete {
|
|||||||
this.tx.emit(tx);
|
this.tx.emit(tx);
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
preventBlur() {
|
|
||||||
// used to notify parent that autocomplete has been interacted with and
|
|
||||||
// that it should not try to do any onBlur() stuff
|
|
||||||
this.interact.emit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -36,16 +36,16 @@
|
|||||||
<div class="row" (click)="editTransaction(item, $event)" [ngClass]="{odd: !(i % 2), editing: item.editing}">
|
<div class="row" (click)="editTransaction(item, $event)" [ngClass]="{odd: !(i % 2), editing: item.editing}">
|
||||||
<div class="col custom-3 date">
|
<div class="col custom-3 date">
|
||||||
<span *ngIf="!item.editing" class="date">{{item.tx.date | date:"M/d/y"}}</span>
|
<span *ngIf="!item.editing" class="date">{{item.tx.date | date:"M/d/y"}}</span>
|
||||||
<input *ngIf="item.editing" type="date" formControlName="date" placeholder="Date" class="form-control" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)"/>
|
<input *ngIf="item.editing" type="date" formControlName="date" placeholder="Date" class="form-control" (keyup.enter)="onEnter(item, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-7 description">
|
<div class="col custom-7 description">
|
||||||
<div *ngIf="!item.editing">{{item.tx.description}}</div>
|
<div *ngIf="!item.editing" class="description">{{item.tx.description}}</div>
|
||||||
<input *ngIf="item.editing" type="text" formControlName="description" placeholder="Description" class="form-control" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)"/>
|
<input *ngIf="item.editing" type="text" formControlName="description" placeholder="Description" class="form-control" (keyup.enter)="onEnter(item, $event)"/>
|
||||||
<tx-autocomplete [item]="item" [accountId]="accountId" (tx)="autocomplete(item, $event)" (interact)="preventBlur(item)"></tx-autocomplete>
|
<tx-autocomplete [item]="item" [accountId]="accountId" (tx)="autocomplete(item, $event)"></tx-autocomplete>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-5 transfer">
|
<div class="col custom-5 transfer">
|
||||||
<span *ngIf="!item.editing" class="transfer">{{getTransferString(item) | slice:0:50}}</span>
|
<span *ngIf="!item.editing" class="transfer">{{getTransferString(item) | slice:0:50}}</span>
|
||||||
<select *ngIf="item.editing" class="form-control" formControlName="accountId" [attr.disabled]="item.showSplits ? '' : null" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)">
|
<select *ngIf="item.editing" class="form-control" formControlName="accountId" [attr.disabled]="item.showSplits ? '' : null" (keyup.enter)="onEnter(item, $event)">
|
||||||
<option *ngFor="let account of selectAccounts" [value]="account.id">
|
<option *ngFor="let account of selectAccounts" [value]="account.id">
|
||||||
{{account.fullName | slice:0:50}}
|
{{account.fullName | slice:0:50}}
|
||||||
</option>
|
</option>
|
||||||
@@ -53,11 +53,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col custom-3 debit">
|
<div class="col custom-3 debit">
|
||||||
<span *ngIf="!item.editing" class="debit">{{getDebit(item) | currencyFormat:account.precision:account.currency}}</span>
|
<span *ngIf="!item.editing" class="debit">{{getDebit(item) | currencyFormat:account.precision:account.currency}}</span>
|
||||||
<input *ngIf="item.editing" type="text" formControlName="debit" placeholder="Debit" class="form-control" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)"/>
|
<input *ngIf="item.editing" type="text" formControlName="debit" placeholder="Debit" class="form-control" (keyup.enter)="onEnter(item, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-3 credit">
|
<div class="col custom-3 credit">
|
||||||
<span *ngIf="!item.editing" class="credit">{{getCredit(item) | currencyFormat:account.precision:account.currency}}</span>
|
<span *ngIf="!item.editing" class="credit">{{getCredit(item) | currencyFormat:account.precision:account.currency}}</span>
|
||||||
<input *ngIf="item.editing" type="text" formControlName="credit" placeholder="Credit" class="form-control" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)"/>
|
<input *ngIf="item.editing" type="text" formControlName="credit" placeholder="Credit" class="form-control" (keyup.enter)="onEnter(item, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-3 balance" [ngClass]="{'negative': item.balance < 0}">
|
<div class="col custom-3 balance" [ngClass]="{'negative': item.balance < 0}">
|
||||||
<span *ngIf="!item.editing" class="balance">{{item.balance | currencyFormat:account.precision:account.currency}}</span>
|
<span *ngIf="!item.editing" class="balance">{{item.balance | currencyFormat:account.precision:account.currency}}</span>
|
||||||
@@ -70,33 +70,29 @@
|
|||||||
<button *ngIf="item.tx.id" class="dropdown-item" (click)="deleteTransaction(item)">Delete</button>
|
<button *ngIf="item.tx.id" class="dropdown-item" (click)="deleteTransaction(item)">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <a *ngIf="item.editing" [routerLink]="" (click)="addSplit(item)" (mousedown)="preventBlur(item)">Split</a><br/>
|
|
||||||
<a *ngIf="item.editing" [routerLink]="" (click)="advancedEdit(item)" (mousedown)="preventBlur(item)">Advanced Edit</a><br/>
|
|
||||||
<a *ngIf="item.editing && item.tx.id" [routerLink]="" (click)="deleteTransaction(item)" (mousedown)="preventBlur(item)">Delete</a> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" *ngFor="let split of item.form.get('splits').controls; let i=index" [formGroup]="split">
|
<div class="row" *ngFor="let split of item.form.get('splits').controls; let i=index" [formGroup]="split">
|
||||||
<div class="col custom-3">
|
<div class="col custom-3">
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-7 add-split">
|
<div class="col custom-7 add-split">
|
||||||
<a [routerLink]="" (click)="deleteSplit(item, i)" (mousedown)="preventBlur(item)">Remove Split</a>
|
<a [routerLink]="" (click)="deleteSplit(item, i)">Remove Split</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-5">
|
<div class="col custom-5">
|
||||||
<select class="form-control" formControlName="accountId" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)">
|
<select class="form-control" formControlName="accountId" (keyup.enter)="onEnter(item, $event)">
|
||||||
<option *ngFor="let account of selectAccounts" [value]="account.id">
|
<option *ngFor="let account of selectAccounts" [value]="account.id">
|
||||||
{{account.fullName}}
|
{{account.fullName}}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-3 debit">
|
<div class="col custom-3 debit">
|
||||||
<input type="text" formControlName="debit" placeholder="Debit" class="form-control" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)"/>
|
<input type="text" formControlName="debit" placeholder="Debit" class="form-control" (keyup.enter)="onEnter(item, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-3 credit">
|
<div class="col custom-3 credit">
|
||||||
<input type="text" formControlName="credit" placeholder="Credit" class="form-control" (keyup.enter)="onEnter(item, $event)" (blur)="onBlur(item, $event)"/>
|
<input type="text" formControlName="credit" placeholder="Credit" class="form-control" (keyup.enter)="onEnter(item, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col custom-3 add-split">
|
<div class="col custom-3 add-split">
|
||||||
<a *ngIf="i === item.form.get('splits').controls.length - 1" [routerLink]="" (click)="addSplit(item)">Add Split</a>
|
<a *ngIf="i === item.form.get('splits').controls.length - 1" [routerLink]="" (click)="addSplit(item)">Add Split</a>
|
||||||
<!-- <button type="submit">hidden submit</button> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit, ViewChild, ElementRef, AfterViewChecked, Renderer } from '@angular/core';
|
import { Component, Input, OnInit, ViewChild, ElementRef, AfterViewChecked, Renderer, HostListener} from '@angular/core';
|
||||||
import { Logger } from '../core/logger';
|
import { Logger } from '../core/logger';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { TransactionService } from '../core/transaction.service';
|
import { TransactionService } from '../core/transaction.service';
|
||||||
@@ -57,7 +57,8 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private renderer: Renderer,
|
private renderer: Renderer,
|
||||||
private modalService: NgbModal
|
private modalService: NgbModal,
|
||||||
|
private eRef: ElementRef
|
||||||
) {
|
) {
|
||||||
this.items = [];
|
this.items = [];
|
||||||
this.limit = 50;
|
this.limit = 50;
|
||||||
@@ -124,6 +125,42 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostListener('document:click', ['$event'])
|
||||||
|
clickout(event) {
|
||||||
|
let clickedForm = false;
|
||||||
|
let txId = undefined;
|
||||||
|
let autocomplete = false;
|
||||||
|
event.path.forEach((elem) => {
|
||||||
|
if(elem.classList && elem.classList.contains('autocomplete')) {
|
||||||
|
autocomplete = true;
|
||||||
|
}
|
||||||
|
if(elem.id && elem.id.indexOf('form') === 0) {
|
||||||
|
clickedForm = true;
|
||||||
|
if(elem.id.indexOf('undefined') === -1) {
|
||||||
|
txId = elem.id.substring(4, 36);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(autocomplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items.forEach(item => {
|
||||||
|
if(item.editing && (item.tx.id !== txId || !clickedForm)) {
|
||||||
|
if(!item.form.pristine) {
|
||||||
|
this.submit(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
item.form = this.fb.group({
|
||||||
|
splits: this.fb.array([])
|
||||||
|
});
|
||||||
|
|
||||||
|
item.editing = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fetchMoreTransactions() {
|
fetchMoreTransactions() {
|
||||||
this.fetching = true;
|
this.fetching = true;
|
||||||
this.log.debug('Fetching ' + this.limit + ' more transactions');
|
this.log.debug('Fetching ' + this.limit + ' more transactions');
|
||||||
@@ -446,49 +483,6 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
// })
|
// })
|
||||||
item.edit$.next(null);
|
item.edit$.next(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
preventBlur(item: TxItem) {
|
|
||||||
this.log.debug('prevent blur');
|
|
||||||
item.preventBlur = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onBlur(item: TxItem, $event) {
|
|
||||||
this.log.debug('blur2');
|
|
||||||
let elem = document.activeElement as any;
|
|
||||||
|
|
||||||
if(elem.form && elem.form.id === 'form' + item.tx.id + item.activeSplitIndex) {
|
|
||||||
// no blur if newly clicked element is in the same form
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.log.debug('blur', item.form.pristine);
|
|
||||||
if(item.preventBlur) {
|
|
||||||
item.preventBlur = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let elem = document.activeElement as any;
|
|
||||||
if(elem.form && elem.form.id === 'form' + item.tx.id + item.activeSplitIndex) {
|
|
||||||
// no blur if newly clicked element is in the same form
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!item.form.pristine) {
|
|
||||||
// if there are changes, submit the form
|
|
||||||
$event.target.blur();
|
|
||||||
this.submit(item);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.form = this.fb.group({
|
|
||||||
splits: this.fb.array([])
|
|
||||||
});
|
|
||||||
|
|
||||||
item.editing = false;
|
|
||||||
}, 100); // timeout needs to be longer than in editTransaction
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteSplit(item: TxItem, index) {
|
deleteSplit(item: TxItem, index) {
|
||||||
item.form.markAsDirty();
|
item.form.markAsDirty();
|
||||||
this.log.debug('delete split');
|
this.log.debug('delete split');
|
||||||
@@ -623,6 +617,7 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
this.log.debug(item.form.value);
|
this.log.debug(item.form.value);
|
||||||
|
|
||||||
if(item.form.pristine) {
|
if(item.form.pristine) {
|
||||||
|
item.editing = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,8 +776,6 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onEnter(item, $event) {
|
onEnter(item, $event) {
|
||||||
item.preventBlur = true;
|
|
||||||
$event.target.blur();
|
|
||||||
this.submit(item);
|
this.submit(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -851,6 +844,7 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
let formDate = Util.getDateFromLocalDateString(item.form.value.date);
|
let formDate = Util.getDateFromLocalDateString(item.form.value.date);
|
||||||
item.tx = new Transaction(
|
item.tx = new Transaction(
|
||||||
{
|
{
|
||||||
|
id: item.tx.id,
|
||||||
date: this.computeTransactionDate(formDate, new Date()),
|
date: this.computeTransactionDate(formDate, new Date()),
|
||||||
description: tx.description,
|
description: tx.description,
|
||||||
splits: tx.splits
|
splits: tx.splits
|
||||||
@@ -871,7 +865,6 @@ export class TxListPage implements OnInit, AfterViewChecked {
|
|||||||
this.log.debug(tx);
|
this.log.debug(tx);
|
||||||
|
|
||||||
item.editing = false;
|
item.editing = false;
|
||||||
item.preventBlur = true;
|
|
||||||
this.editTransaction(item, {target: {className: 'description', classList: ['description']}});
|
this.editTransaction(item, {target: {className: 'description', classList: ['description']}});
|
||||||
item.form.markAsDirty();
|
item.form.markAsDirty();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,5 @@ export class TxItem {
|
|||||||
form: FormGroup;
|
form: FormGroup;
|
||||||
balance: number;
|
balance: number;
|
||||||
editing: boolean;
|
editing: boolean;
|
||||||
preventBlur: boolean;
|
|
||||||
edit$: Subject<any>;
|
edit$: Subject<any>;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user