started to implement updates on transactions
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -12,6 +12,8 @@ public interface AccountDb {
|
||||
|
||||
Account loadAccount(long accountId);
|
||||
|
||||
Transaction loadTransaction(long transactionId);
|
||||
|
||||
List<Transaction> loadTransactions(Account account);
|
||||
|
||||
Account save(Account account);
|
||||
|
||||
@@ -63,6 +63,30 @@ public class AccountingModule extends BaseHandler implements AccountingService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPatch(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
try {
|
||||
var user = userService().refreshSession(ex);
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head) {
|
||||
case TRANSACTION -> {
|
||||
try {
|
||||
var tid = Long.parseLong(path.pop());
|
||||
yield patchTransaction(user.get(),tid,ex);
|
||||
} catch (NumberFormatException ignored) {
|
||||
yield super.doPatch(path,ex);
|
||||
}
|
||||
|
||||
}
|
||||
case null, default -> super.doPatch(path, ex);
|
||||
};
|
||||
} catch (UmbrellaException e){
|
||||
return send(ex,e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPost(Path path, HttpExchange ex) throws IOException {
|
||||
addCors(ex);
|
||||
@@ -131,6 +155,18 @@ public class AccountingModule extends BaseHandler implements AccountingService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean patchTransaction(UmbrellaUser user, long transactionId, HttpExchange ex) throws IOException {
|
||||
var transaction = accountDb.loadTransaction(transactionId);
|
||||
LOG.log(WARNING,"Missing permission check in patchTransaction(…)!");
|
||||
var json = json(ex);
|
||||
if (json.has(Field.DATE)){
|
||||
var date = LocalDate.parse(json.getString(Field.DATE));
|
||||
transaction.date(date);
|
||||
accountDb.save(transaction);
|
||||
}
|
||||
return sendContent(ex,transaction);
|
||||
}
|
||||
|
||||
private boolean postEntry(UmbrellaUser user, HttpExchange ex) throws IOException {
|
||||
var json = json(ex);
|
||||
if (!json.has(Field.ACCOUNT)) throw missingField(Field.ACCOUNT);
|
||||
|
||||
@@ -6,6 +6,7 @@ import static de.srsoftware.tools.jdbc.Condition.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.umbrella.accounting.Constants.*;
|
||||
import static de.srsoftware.umbrella.core.constants.Field.ID;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
||||
import static de.srsoftware.umbrella.core.model.Translatable.t;
|
||||
import static java.text.MessageFormat.format;
|
||||
@@ -51,7 +52,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
);""";
|
||||
|
||||
try {
|
||||
sql = format(sql,TABLE_ACCOUNTS, Field.ID, Field.NAME, Field.OWNER, Field.CURRENCY);
|
||||
sql = format(sql,TABLE_ACCOUNTS, ID, Field.NAME, Field.OWNER, Field.CURRENCY);
|
||||
var stmt = db.prepareStatement(sql);
|
||||
stmt.execute();
|
||||
stmt.close();
|
||||
@@ -68,7 +69,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
);
|
||||
""";
|
||||
try {
|
||||
sql = format(sql,TABLE_TAGS,Field.ID,Field.TAG);
|
||||
sql = format(sql,TABLE_TAGS, ID,Field.TAG);
|
||||
var stmt = db.prepareStatement(sql);
|
||||
stmt.execute();
|
||||
stmt.close();
|
||||
@@ -107,7 +108,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
{6} TEXT
|
||||
);""";
|
||||
try {
|
||||
sql = format(sql,TABLE_TRANSACTIONS,Field.ACCOUNT,Field.TIMESTAMP,Field.SOURCE,Field.DESTINATION, Field.AMOUNT,Field.DESCRIPTION, Field.ID);
|
||||
sql = format(sql,TABLE_TRANSACTIONS,Field.ACCOUNT,Field.TIMESTAMP,Field.SOURCE,Field.DESTINATION, Field.AMOUNT,Field.DESCRIPTION, ID);
|
||||
var stmt = db.prepareStatement(sql);
|
||||
stmt.execute();
|
||||
stmt.close();
|
||||
@@ -127,7 +128,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
while (rs.next()) accountIds.add(rs.getLong(1));
|
||||
rs.close();
|
||||
var accounts = new HashSet<Account>();
|
||||
rs = select(ALL).from(TABLE_ACCOUNTS).where(Field.ID, Condition.in(accountIds.toArray())).exec(db);
|
||||
rs = select(ALL).from(TABLE_ACCOUNTS).where(ID, Condition.in(accountIds.toArray())).exec(db);
|
||||
while (rs.next()) accounts.add(Account.of(rs));
|
||||
rs.close();
|
||||
return accounts;
|
||||
@@ -139,7 +140,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
@Override
|
||||
public Account loadAccount(long accountId) {
|
||||
try {
|
||||
var rs = select(ALL).from(TABLE_ACCOUNTS).where(Field.ID,equal(accountId)).exec(db);
|
||||
var rs = select(ALL).from(TABLE_ACCOUNTS).where(ID,equal(accountId)).exec(db);
|
||||
Account account = null;
|
||||
if (rs.next()) account = Account.of(rs);
|
||||
rs.close();
|
||||
@@ -150,6 +151,20 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transaction loadTransaction(long transactionId) {
|
||||
try {
|
||||
Transaction transaction = null;
|
||||
var rs = select(ALL).from(TABLE_TRANSACTIONS).where(ID,equal(transactionId)).exec(db);
|
||||
if (rs.next()) transaction = Transaction.of(rs);
|
||||
rs.close();
|
||||
if (transaction != null) return transaction;
|
||||
throw failedToLoadObject(Text.TRANSACTION,transactionId);
|
||||
} catch (SQLException e) {
|
||||
throw failedToLoadObject(Text.TRANSACTION);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Transaction> loadTransactions(Account account) {
|
||||
try {
|
||||
@@ -161,7 +176,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
}
|
||||
rs.close();
|
||||
var transactionIds = transactions.keySet().toArray();
|
||||
rs = select(ALL).from(TABLE_TAGS_TRANSACTIONS).leftJoin(Field.TAG_ID,TABLE_TAGS,Field.ID).where(Field.TRANSACTION_ID,in(transactionIds)).exec(db);
|
||||
rs = select(ALL).from(TABLE_TAGS_TRANSACTIONS).leftJoin(Field.TAG_ID,TABLE_TAGS, ID).where(Field.TRANSACTION_ID,in(transactionIds)).exec(db);
|
||||
while (rs.next()) {
|
||||
var transaction = transactions.get(rs.getLong(Field.TRANSACTION_ID));
|
||||
if (transaction != null) transaction.tags().add(rs.getString(Field.TAG));
|
||||
@@ -191,9 +206,9 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
|
||||
@Override
|
||||
public Transaction save(Transaction transaction) {
|
||||
var timestamp = transaction.date().toEpochSecond(ZoneOffset.UTC);
|
||||
if (transaction.id() == 0) {
|
||||
try {
|
||||
var timestamp = transaction.date().toEpochSecond(ZoneOffset.UTC);
|
||||
var rs = Query.insertInto(TABLE_TRANSACTIONS, Field.ACCOUNT, Field.TIMESTAMP, Field.SOURCE, Field.DESTINATION, Field.AMOUNT, Field.DESCRIPTION)
|
||||
.values(transaction.accountId(), timestamp, transaction.source().value(), transaction.destination().value(), transaction.amount(), transaction.purpose())
|
||||
.execute(db).getGeneratedKeys();
|
||||
@@ -202,8 +217,15 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
} catch (SQLException e) {
|
||||
throw failedToStoreObject(transaction);
|
||||
}
|
||||
} else { // TODO : implement update
|
||||
throw UmbrellaException.failedToStoreObject(transaction);
|
||||
} else {
|
||||
try {
|
||||
Query.replaceInto(TABLE_TRANSACTIONS, Field.ID, Field.ACCOUNT, Field.TIMESTAMP, Field.SOURCE, Field.DESTINATION, Field.AMOUNT, Field.DESCRIPTION)
|
||||
.values(transaction.id(), transaction.accountId(), timestamp, transaction.source().value(), transaction.destination().value(), transaction.amount(), transaction.purpose())
|
||||
.execute(db).close();
|
||||
return transaction;
|
||||
} catch (SQLException e) {
|
||||
throw failedToStoreObject(transaction);
|
||||
}
|
||||
}
|
||||
return saveTags(transaction);
|
||||
}
|
||||
@@ -213,7 +235,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
var existingTags = new HashMap<String,Long>();
|
||||
try {
|
||||
var rs = select(ALL).from(TABLE_TAGS).where(Field.TAG,in(transaction.tags().toArray())).exec(db);
|
||||
while (rs.next()) existingTags.put(rs.getString(Field.TAG), rs.getLong(Field.ID));
|
||||
while (rs.next()) existingTags.put(rs.getString(Field.TAG), rs.getLong(ID));
|
||||
rs.close();
|
||||
} catch (SQLException e){
|
||||
throw failedToLoadMembers(transaction);
|
||||
@@ -257,7 +279,7 @@ public class SqliteDb extends BaseDb implements AccountDb {
|
||||
public Set<String> searchTagsContaining(String key, long accountId) {
|
||||
try {
|
||||
var tags = new HashSet<String>();
|
||||
var rs = select(ALL).from(TABLE_TRANSACTIONS).leftJoin(Field.ID,TABLE_TAGS_TRANSACTIONS,Field.TRANSACTION_ID).leftJoin(Field.TAG_ID,TABLE_TAGS,Field.ID).where(Field.TAG,like(format("%{0}%",key))).exec(db);
|
||||
var rs = select(ALL).from(TABLE_TRANSACTIONS).leftJoin(ID,TABLE_TAGS_TRANSACTIONS,Field.TRANSACTION_ID).leftJoin(Field.TAG_ID,TABLE_TAGS, ID).where(Field.TAG,like(format("%{0}%",key))).exec(db);
|
||||
while (rs.next()) tags.add(rs.getString(Field.TAG));
|
||||
rs.close();
|
||||
return tags;
|
||||
|
||||
@@ -53,9 +53,10 @@ public class Path {
|
||||
public static final String STATE = "state";
|
||||
public static final String STOP = "stop";
|
||||
|
||||
public static final String TAGS = "tags";
|
||||
public static final String TAGGED = "tagged";
|
||||
public static final String TOKEN = "token";
|
||||
public static final String TAGS = "tags";
|
||||
public static final String TAGGED = "tagged";
|
||||
public static final String TRANSACTION = "transaction";
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
public static final String USER = "user";
|
||||
public static final String USES = "uses";
|
||||
|
||||
@@ -78,6 +78,7 @@ public class Text {
|
||||
public static final String TASKS = "tasks";
|
||||
public static final String TIMETRACKING = "timetracking";
|
||||
public static final String TIME_WITH_ID = "time ({id})";
|
||||
public static final String TRANSACTION = "transaction";
|
||||
public static final String TYPE = "type";
|
||||
|
||||
public static final String UNIT = "unit";
|
||||
|
||||
@@ -5,6 +5,7 @@ import de.srsoftware.tools.Mappable;
|
||||
import de.srsoftware.umbrella.core.constants.Field;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.HashSet;
|
||||
@@ -13,8 +14,53 @@ import java.util.Set;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
|
||||
public record Transaction(long id, long accountId, LocalDateTime date, IdOrString source, IdOrString destination, double amount, String purpose, Set<String> tags) implements Mappable {
|
||||
public class Transaction implements Mappable {
|
||||
private long accountId, id;
|
||||
private LocalDateTime date;
|
||||
private IdOrString source, destination;
|
||||
private double amount;
|
||||
private String purpose;
|
||||
private Set<String> tags;
|
||||
|
||||
public Transaction(long id, long accountId, LocalDateTime date, IdOrString source, IdOrString destination, double amount, String purpose, Set<String> tags){
|
||||
this.id = id;
|
||||
this.accountId = accountId;
|
||||
this.date = date;
|
||||
this.source = source;
|
||||
this.destination = destination;
|
||||
this.amount = amount;
|
||||
this.purpose = purpose;
|
||||
this.tags = tags == null ? new HashSet<>() : tags;
|
||||
}
|
||||
|
||||
public long accountId(){
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public double amount(){
|
||||
return amount;
|
||||
}
|
||||
|
||||
public LocalDateTime date(){
|
||||
return date;
|
||||
}
|
||||
|
||||
public Transaction date(LocalDateTime newVal){
|
||||
date = newVal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void date(LocalDate date) {
|
||||
this.date = this.date.withYear(date.getYear()).withMonth(date.getMonthValue()).withDayOfMonth(date.getDayOfMonth());
|
||||
}
|
||||
|
||||
public IdOrString destination(){
|
||||
return destination;
|
||||
}
|
||||
|
||||
public long id(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public static Transaction of(ResultSet rs) throws SQLException {
|
||||
var accountId = rs.getLong(Field.ACCOUNT);
|
||||
@@ -25,7 +71,19 @@ public record Transaction(long id, long accountId, LocalDateTime date, IdOrStrin
|
||||
var amount = rs.getDouble(Field.AMOUNT);
|
||||
var purpose = rs.getString(Field.DESCRIPTION);
|
||||
var id = rs.getLong(Field.ID);
|
||||
return new Transaction(id, accountId, date, source, destination, amount, purpose, new HashSet<>());
|
||||
return new Transaction(id, accountId, date, source, destination, amount, purpose, null);
|
||||
}
|
||||
|
||||
public String purpose(){
|
||||
return purpose;
|
||||
}
|
||||
|
||||
public IdOrString source(){
|
||||
return source;
|
||||
}
|
||||
|
||||
public Set<String> tags(){
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
onclick = evt => { evt.preventDefault(); startEdit(); return false },
|
||||
onSet = newVal => {return true;},
|
||||
title = t('click_to_edit'),
|
||||
type = 'div',
|
||||
value = $bindable(null)
|
||||
type = 'text',
|
||||
value = $bindable(null),
|
||||
wrapper = 'div'
|
||||
} = $props();
|
||||
|
||||
let editing = $state(simple);
|
||||
@@ -110,7 +111,7 @@
|
||||
</style>
|
||||
|
||||
{#if editable && editing}
|
||||
<input bind:value={editValue} onkeyup={typed} {title} autofocus />
|
||||
<input bind:value={editValue} onkeyup={typed} {title} {type} autofocus />
|
||||
{:else}
|
||||
<svelte:element this={type} href={href} onclick={ignore} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} {oncontextmenu} class={{editable}} {title} >{value}</svelte:element>
|
||||
<svelte:element this={wrapper} href={href} onclick={ignore} {onmousedown} {onmouseup} {ontouchstart} {ontouchend} {oncontextmenu} class={{editable}} {title} >{value}</svelte:element>
|
||||
{/if}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import { t } from '../../translations.svelte';
|
||||
|
||||
import EntryForm from './add_entry.svelte';
|
||||
import Transaction from './transaction.svelte';
|
||||
|
||||
let { id } = $props();
|
||||
let account = $state(null);
|
||||
@@ -67,31 +68,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each transactions as transaction, i}
|
||||
<tr>
|
||||
<td>{transaction.date}</td>
|
||||
{#each Object.entries(users) as [id,user]}
|
||||
<td class="amount">
|
||||
{#if id == transaction.source.id}
|
||||
{(-transaction.amount).toFixed(2)} {account.currency}
|
||||
{/if}
|
||||
{#if id == transaction.destination.id}
|
||||
{(+transaction.amount).toFixed(2)} {account.currency}
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
<td class="party">
|
||||
{#if !transaction.source.id}
|
||||
← {transaction.source.value}
|
||||
{/if}
|
||||
{#if !transaction.destination.id}
|
||||
→ {transaction.destination.value}
|
||||
{/if}
|
||||
</td>
|
||||
<td class="purpose">{transaction.purpose}</td>
|
||||
<td class="tags">
|
||||
{transaction.tags.join(', ')}
|
||||
</td>
|
||||
</tr>
|
||||
<Transaction {account} {transaction} {users} />
|
||||
{/each}
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
49
frontend/src/routes/accounting/transaction.svelte
Normal file
49
frontend/src/routes/accounting/transaction.svelte
Normal file
@@ -0,0 +1,49 @@
|
||||
<script>
|
||||
import LineEditor from '../../Components/LineEditor.svelte';
|
||||
import { api, patch } from '../../urls.svelte';
|
||||
import { error, yikes } from '../../warn.svelte';
|
||||
let { account, transaction, users } = $props();
|
||||
|
||||
async function update(changes){
|
||||
let url = api('accounting/transaction/'+transaction.id);
|
||||
let res = await patch(url,changes);
|
||||
if (res.ok){
|
||||
yikes();
|
||||
return true;
|
||||
}
|
||||
error(res);
|
||||
return false;
|
||||
}
|
||||
|
||||
async function setDate(newDate){
|
||||
return await update({date:newDate});
|
||||
}
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<LineEditor type="date" wrapper="span" editable="true" value={transaction.date} onSet={setDate} />
|
||||
</td>
|
||||
{#each Object.entries(users) as [id,user]}
|
||||
<td class="amount">
|
||||
{#if id == transaction.source.id}
|
||||
{(-transaction.amount).toFixed(2)} {account.currency}
|
||||
{/if}
|
||||
{#if id == transaction.destination.id}
|
||||
{(+transaction.amount).toFixed(2)} {account.currency}
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
<td class="party">
|
||||
{#if !transaction.source.id}
|
||||
← {transaction.source.value}
|
||||
{/if}
|
||||
{#if !transaction.destination.id}
|
||||
→ {transaction.destination.value}
|
||||
{/if}
|
||||
</td>
|
||||
<td class="purpose">{transaction.purpose}</td>
|
||||
<td class="tags">
|
||||
{transaction.tags.join(', ')}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -36,11 +36,11 @@
|
||||
<span class="symbol {home?'':'inactive'}" onclick={toggleHome}></span>
|
||||
<span class="symbol {work?'':'inactive'}" onclick={toggleWork} ></span>
|
||||
</div>
|
||||
<LineEditor type="span" editable={true} value={address.box} onSet={newVal => onSet(address.box,newVal)} title={t('post_box')} />
|
||||
<LineEditor type="span" editable={true} value={address.ext} onSet={newVal => onSet(address.ext,newVal)} title={t('extended_address')} />
|
||||
<LineEditor type="span" editable={true} value={address.street} onSet={newVal => onSet(address.street,newVal)} title={t('street')} />
|
||||
<LineEditor type="span" editable={true} value={address.post_code} onSet={newVal => onSet(address.post_code,newVal)} title={t('post_code')} />
|
||||
<LineEditor type="span" editable={true} value={address.locality} onSet={newVal => onSet(address.locality,newVal)} title={t('locality')} />
|
||||
<LineEditor type="span" editable={true} value={address.region} onSet={newVal => onSet(address.region,newVal)} title={t('region')} />
|
||||
<LineEditor type="span" editable={true} value={address.country} onSet={newVal => onSet(address.country,newVal)} title={t('country')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.box} onSet={newVal => onSet(address.box,newVal)} title={t('post_box')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.ext} onSet={newVal => onSet(address.ext,newVal)} title={t('extended_address')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.street} onSet={newVal => onSet(address.street,newVal)} title={t('street')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.post_code} onSet={newVal => onSet(address.post_code,newVal)} title={t('post_code')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.locality} onSet={newVal => onSet(address.locality,newVal)} title={t('locality')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.region} onSet={newVal => onSet(address.region,newVal)} title={t('region')} />
|
||||
<LineEditor wrapper="span" editable={true} value={address.country} onSet={newVal => onSet(address.country,newVal)} title={t('country')} />
|
||||
</div>
|
||||
@@ -33,5 +33,5 @@
|
||||
{#if value}
|
||||
<span class="symbol {home?'':'inactive'}" onclick={toggleHome}></span>
|
||||
<span class="symbol {work?'':'inactive'}" onclick={toggleWork} ></span>
|
||||
<LineEditor type="span" editable={true} {value} {onSet} /><br/>
|
||||
<LineEditor wrapper="span" editable={true} {value} {onSet} /><br/>
|
||||
{/if}
|
||||
@@ -19,7 +19,7 @@
|
||||
{#if field.value.includes('\\n')}
|
||||
<MultiLineEditor type="div" editable={true} value={field.value.replaceAll('\\n','\n')} {onSet} title={t(field.name)+' – '+t('right_click_to_edit')} />
|
||||
{:else}
|
||||
<LineEditor type="div" editable={true} value={field.value} {onSet} title={t(field.name)+' – '+t('click_to_edit')} />
|
||||
<LineEditor editable={true} value={field.value} {onSet} title={t(field.name)+' – '+t('click_to_edit')} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -14,5 +14,5 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<LineEditor type="span" editable={true} {value} {onSet} title={t('formatted_name')}/>
|
||||
<LineEditor wrapper="span" editable={true} {value} {onSet} title={t('formatted_name')}/>
|
||||
{/if}
|
||||
@@ -16,18 +16,18 @@
|
||||
|
||||
<div class="name">
|
||||
{#if n.prefix}
|
||||
<LineEditor type="span" editable={true} value={n.prefix} onSet={newVal => onSet(n.prefix,newVal)} title={t('name_prefix')} />
|
||||
<LineEditor wrapper="span" editable={true} value={n.prefix} onSet={newVal => onSet(n.prefix,newVal)} title={t('name_prefix')} />
|
||||
{/if}
|
||||
{#if n.given}
|
||||
<LineEditor type="span" editable={true} value={n.given} onSet={newVal => onSet(n.given,newVal)} title={t('given_name')} />
|
||||
<LineEditor wrapper="span" editable={true} value={n.given} onSet={newVal => onSet(n.given,newVal)} title={t('given_name')} />
|
||||
{/if}
|
||||
{#if n.additional}
|
||||
<LineEditor type="span" editable={true} value={n.additional} onSet={newVal => onSet(n.additional,newVal)} title={t('additional_name')} />
|
||||
<LineEditor wrapper="span" editable={true} value={n.additional} onSet={newVal => onSet(n.additional,newVal)} title={t('additional_name')} />
|
||||
{/if}
|
||||
{#if n.family}
|
||||
<LineEditor type="span" editable={true} value={n.family} onSet={newVal => onSet(n.family,newVal)} title={t('family_name')} />
|
||||
<LineEditor wrapper="span" editable={true} value={n.family} onSet={newVal => onSet(n.family,newVal)} title={t('family_name')} />
|
||||
{/if}
|
||||
{#if n.suffix}
|
||||
<LineEditor type="span" editable={true} value={n.suffix} onSet={newVal => onSet(n.suffix,newVal)} title={t('<name_suffix></name_suffix>')} />
|
||||
<LineEditor wrapper="span" editable={true} value={n.suffix} onSet={newVal => onSet(n.suffix,newVal)} title={t('<name_suffix></name_suffix>')} />
|
||||
{/if}
|
||||
</div>
|
||||
@@ -39,5 +39,5 @@
|
||||
<span class="symbol {cell?'':'inactive'}" onclick={toggleCell} ></span>
|
||||
<span class="symbol {home?'':'inactive'}" onclick={toggleHome}></span>
|
||||
<span class="symbol {work?'':'inactive'}" onclick={toggleWork} ></span>
|
||||
<LineEditor type="span" editable={true} {value} {onSet} /><br/>
|
||||
<LineEditor wrapper="span" editable={true} {value} {onSet} /><br/>
|
||||
{/if}
|
||||
@@ -14,5 +14,5 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<LineEditor type="span" editable={true} {value} {onSet} title={t('organization')}/>
|
||||
<LineEditor wrapper="span" editable={true} {value} {onSet} title={t('organization')}/>
|
||||
{/if}
|
||||
@@ -14,5 +14,5 @@
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
<LineEditor type="div" editable={true} {value} {onSet} title={t('url')}/>
|
||||
<LineEditor editable={true} {value} {onSet} title={t('url')}/>
|
||||
{/if}
|
||||
@@ -263,7 +263,7 @@
|
||||
<div class="items">
|
||||
{#if location}
|
||||
<h3>
|
||||
<LineEditor editable={true} bind:value={location.name} type="span" onSet={newName => patchLocation(location,'name',newName)} />
|
||||
<LineEditor editable={true} bind:value={location.name} wrapper="span" onSet={newName => patchLocation(location,'name',newName)} />
|
||||
<button class="symbol" title={t('delete_object',{object:t('location')})} onclick={e => deleteLocation(location)}></button>
|
||||
{#if location.parent_location_id}
|
||||
<button class="symbol" title={t('move_to_top')} onclick={e => moveToTop(location)}></button>
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
</script>
|
||||
|
||||
{#if item}
|
||||
<LineEditor type="h3" editable={true} value={item.name} onSet={v => update('name',v)} />
|
||||
<LineEditor wrapper="h3" editable={true} value={item.name} onSet={v => update('name',v)} />
|
||||
<button class="clone symbol" title={t('clone')} onclick={doClone}></button>
|
||||
<div>
|
||||
{@html item.description.rendered}
|
||||
@@ -80,7 +80,7 @@
|
||||
{t('ID')}
|
||||
</td>
|
||||
<td>
|
||||
<LineEditor type="span" editable={true} value={item.code} onSet={v => update('code',v)} />
|
||||
<LineEditor wrapper="span" editable={true} value={item.code} onSet={v => update('code',v)} />
|
||||
</td>
|
||||
</tr>
|
||||
{#each item.properties.toSorted(byName) as prop}
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
|
||||
{#if !deleted}
|
||||
<li draggable="true" {ondrop} ondragover={e => e.preventDefault()} {ondragstart} class="task {states[task.status]?.toLowerCase()}">
|
||||
<LineEditor bind:value={task.name} onclick={openTask} editable={true} onSet={setName} type="a" href={`/task/${task.id}/view`} />
|
||||
<LineEditor bind:value={task.name} onclick={openTask} editable={true} onSet={setName} wrapper="a" href={`/task/${task.id}/view`} />
|
||||
{#if task.est_time}
|
||||
<span class="estimated_time">({+task.est_time} h)</span>
|
||||
{/if}
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
</span>
|
||||
{/each}
|
||||
</div>
|
||||
<LineEditor value={page.title} type="h2" {editable} onSet={t => patchTitle(t)} />
|
||||
<LineEditor value={page.title} wrapper="h2" {editable} onSet={t => patchTitle(t)} />
|
||||
{#if page.version != page.versions[0]}
|
||||
<span class="warn">{t('not_recent_version')}</span>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user