From 2e2b2bb75a680df0a984f5490761181cfbad8b29 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 10 Feb 2025 23:50:45 +0100 Subject: [PATCH 01/16] To balance view add prev/next nav links. --- src/run.py | 1 + src/templates/balance.tmpl | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/run.py b/src/run.py index c7fdad8..644152e 100755 --- a/src/run.py +++ b/src/run.py @@ -440,6 +440,7 @@ class Handler(PlomHttpHandler): ctx['roots'] = [ac for ac in acc_dict.values() if not ac.parent] ctx['valid'] = valid ctx['booking'] = self.server.bookings[id_] + ctx['path_up_incl'] = f'{self.path_toks[1]}?up_incl=' self._send_rendered('balance', ctx) def get_edit(self, ctx, raw: bool) -> None: diff --git a/src/templates/balance.tmpl b/src/templates/balance.tmpl index 59ff4c6..33c31c1 100644 --- a/src/templates/balance.tmpl +++ b/src/templates/balance.tmpl @@ -51,7 +51,12 @@ span.indent { letter-spacing: 3em; } {% endblock css %} {% block content %} -

balance after booking {{booking.id_}} ({{booking.date}}: {{booking.target}})

+

+prev +next +| +balance after booking {{booking.id_}} ({{booking.date}}: {{booking.target}}) +

{% for root in roots %} {{ account_with_children(root, indent=0) }} -- 2.30.2 From d43b0dc3cd0cbe164f45923783d6fe35e6db26b9 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 13 Feb 2025 03:06:58 +0100 Subject: [PATCH 02/16] Fix booking balance tree repeating already-seen parental steps. --- src/run.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/run.py b/src/run.py index 644152e..17cc63b 100755 --- a/src/run.py +++ b/src/run.py @@ -460,8 +460,12 @@ class Handler(PlomHttpHandler): path = '' for step_name in full_name.split(':'): path = ':'.join([path, step_name]) if path else step_name + already_registered = False for child in [n for n in parent_children if path == n['name']]: parent_children = child['children'] + already_registered = True + break + if already_registered: continue wealth_before = accounts_before[path].wealth wealth_after = accounts_after[path].wealth -- 2.30.2 From fdf65ec16872859851f640ca8c9a30d395ea4a39 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 13 Feb 2025 03:19:18 +0100 Subject: [PATCH 03/16] In booking balance, also show accounts of zero diff _if_ they've been directly set in the Booking. --- src/run.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/run.py b/src/run.py index 17cc63b..bafb5bb 100755 --- a/src/run.py +++ b/src/run.py @@ -469,10 +469,14 @@ class Handler(PlomHttpHandler): continue wealth_before = accounts_before[path].wealth wealth_after = accounts_after[path].wealth - diff = {c: a for c, a in (wealth_after - wealth_before - ).moneys.items() - if a != 0} - if diff: + directly_set = full_name == path + diff = { + c: a for c, a in (wealth_after - wealth_before + ).moneys.items() + if a != 0 + or (directly_set + and c in booking.account_changes[full_name].moneys)} + if diff or directly_set: displayed_currencies = set(diff.keys()) for wealth in wealth_before, wealth_after: wealth.ensure_currencies(displayed_currencies) -- 2.30.2 From 25c4a42e37a2fd71ca14c78d5e4d8c854677a89a Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 13 Feb 2025 03:20:58 +0100 Subject: [PATCH 04/16] In Booking balance view, highlight accounts directly targeted in Booking. --- src/run.py | 1 + src/templates/_macros.tmpl | 14 +++++++------- src/templates/edit_structured.tmpl | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/run.py b/src/run.py index bafb5bb..351e1fa 100755 --- a/src/run.py +++ b/src/run.py @@ -483,6 +483,7 @@ class Handler(PlomHttpHandler): wealth.purge_currencies_except(displayed_currencies) node: dict[str, Any] = { 'name': path, + 'directly_set': directly_set, 'wealth_before': wealth_before.moneys, 'wealth_diff': diff, 'wealth_after': wealth_after.moneys, diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index c93ceb9..f5d7943 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -121,33 +121,33 @@ function taint() { {% endmacro %} -{% macro booking_balance_account_with_children(account) %} - -{{account.name}}{% if account.children %}:{% endif %} +{% macro booking_balance_account_with_children(node) %} + +{{node.name}}{% if node.children %}:{% endif %} -{% for curr, amt in account.wealth_before.items() %} +{% for curr, amt in node.wealth_before.items() %} {{ tr_money_balance(amt, curr) }} {% endfor %}
-{% for curr, amt in account.wealth_diff.items() %} +{% for curr, amt in node.wealth_diff.items() %} {{ tr_money_balance(amt, curr) }} {% endfor %}
-{% for curr, amt in account.wealth_after.items() %} +{% for curr, amt in node.wealth_after.items() %} {{ tr_money_balance(amt, curr) }} {% endfor %}
-{% for child in account.children %} +{% for child in node.children %} {{ booking_balance_account_with_children(child) }} {% endfor %} {% endmacro %} diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index 8569dea..ba99349 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -8,6 +8,7 @@ input.date_input, input.number_input { font-family: monospace; } input.number_input { text-align: right; } input.date_input { margin-right: 0.1em; } +tr.directly_set > td { font-weight: bold; } {% endblock %} -- 2.30.2 From 1d0aae9826c77d0297b7ac2df170bc0b7eaf55d5 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 13 Feb 2025 03:44:01 +0100 Subject: [PATCH 05/16] Minimally improve booking balance layout. --- src/templates/_macros.tmpl | 4 ++-- src/templates/edit_structured.tmpl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index f5d7943..85f3b14 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -122,8 +122,8 @@ function taint() { {% macro booking_balance_account_with_children(node) %} - -{{node.name}}{% if node.children %}:{% endif %} + +{{node.name}}{% if node.children %}:{% endif %} {% for curr, amt in node.wealth_before.items() %} diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index ba99349..43a1858 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -8,7 +8,7 @@ input.date_input, input.number_input { font-family: monospace; } input.number_input { text-align: right; } input.date_input { margin-right: 0.1em; } -tr.directly_set > td { font-weight: bold; } +td.directly_set { font-weight: bold; } {% endblock %} -- 2.30.2 From f00ed536bde94f705163c2f13e46d42e12848b14 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 13 Feb 2025 03:45:12 +0100 Subject: [PATCH 06/16] Minor variable name change for better semantical precision. --- src/run.py | 8 ++++---- src/templates/_macros.tmpl | 2 +- src/templates/edit_structured.tmpl | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/run.py b/src/run.py index 351e1fa..e27a438 100755 --- a/src/run.py +++ b/src/run.py @@ -469,21 +469,21 @@ class Handler(PlomHttpHandler): continue wealth_before = accounts_before[path].wealth wealth_after = accounts_after[path].wealth - directly_set = full_name == path + direct_target = full_name == path diff = { c: a for c, a in (wealth_after - wealth_before ).moneys.items() if a != 0 - or (directly_set + or (direct_target and c in booking.account_changes[full_name].moneys)} - if diff or directly_set: + if diff or direct_target: displayed_currencies = set(diff.keys()) for wealth in wealth_before, wealth_after: wealth.ensure_currencies(displayed_currencies) wealth.purge_currencies_except(displayed_currencies) node: dict[str, Any] = { 'name': path, - 'directly_set': directly_set, + 'direct_target': direct_target, 'wealth_before': wealth_before.moneys, 'wealth_diff': diff, 'wealth_after': wealth_after.moneys, diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index 85f3b14..bc98cc1 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -123,7 +123,7 @@ function taint() { {% macro booking_balance_account_with_children(node) %} - + - - - -{% endmacro %} +{% macro table_dat_lines_action_button(dat_line, verb, direction, label, enabled=true) %} + +{% endmacro %} {% macro table_dat_lines(dat_lines, raw) %}
{{node.name}}{% if node.children %}:{% endif %}{{node.name}}{% if node.children %}:{% endif %} {% for curr, amt in node.wealth_before.items() %} diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index 43a1858..ad7450e 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -8,7 +8,7 @@ input.date_input, input.number_input { font-family: monospace; } input.number_input { text-align: right; } input.date_input { margin-right: 0.1em; } -td.directly_set { font-weight: bold; } +td.direct_target { font-weight: bold; } {% endblock %} -- 2.30.2 From 398eab5cfb46c1b5dd544887b3b8c9bb39227dee Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Fri, 14 Feb 2025 22:38:23 +0100 Subject: [PATCH 07/16] Add string replacement button to structured edit view. --- src/templates/edit_structured.tmpl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index ad7450e..298510c 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -157,6 +157,24 @@ function update_form() { }); } +function replace() { + const from = document.getElementById("replace_from").value; + const to = document.getElementById("replace_to").value; + dat_lines.forEach((dat_line) => { + dat_line.comment = dat_line.comment.replaceAll(from, to); + if ('code' in dat_line) { + dat_line.code = dat_line.code.replaceAll(from, to); + } + ['account', 'amount', 'currency'].forEach((key) => { + if (key in dat_line.booking_line) { + dat_line.booking_line[key] = dat_line.booking_line[key].replaceAll(from, to); + } + }); + }); + taint(); + update_form(); +} + window.onload = update_form; {% endblock %} @@ -164,6 +182,12 @@ window.onload = update_form; {% block content %}
{{ macros.edit_bar("raw", id) }} + +from + +to + +
-- 2.30.2 From 5c6102bdbde57c23e1547dd4051fb995ebf16fa7 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 24 Feb 2025 12:48:36 +0100 Subject: [PATCH 08/16] Refactor template code. --- src/templates/_macros.tmpl | 48 +++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index bc98cc1..a1a2764 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -4,44 +4,49 @@ td.amt, td.curr { font-family: monospace; font-size: 1.3em; } {% endmacro %} + {% macro css_td_money_balance() %} td.balance.amt { width: 10em; } td.balance.curr { width: 3em; } {% endmacro %} + {% macro css_errors() %} td.invalid, tr.warning td.invalid { background-color: #ff0000; } {% endmacro %} + {% macro css_ledger_index_col() %} table.ledger tr > td:first-child { background-color: white; } {% endmacro %} -{% macro tr_money_balance(amt, curr) %} -
{{amt}}{{curr|truncate(4,true,"…")}}
{% for dat_line in dat_lines %} + + {% if dat_line.is_intro %} - + [#] + {{ table_dat_lines_action_button(dat_line, "move", "up", "^", dat_line.booking.can_move(1)) }} {% elif dat_line.booking_line.idx == 1 %} - + [b] + {{ table_dat_lines_action_button(dat_line, "move", "down", "v", dat_line.booking.can_move(0)) }} {% elif dat_line.booking_line.idx == 2 %} - - {% else %} - + {{ table_dat_lines_action_button(dat_line, "copy", "here", "c") }} + {{ table_dat_lines_action_button(dat_line, "copy", "to_end", "C") }} {% endif %} + + {% if raw %} {% if dat_line.is_intro %} @@ -52,7 +57,9 @@ table.ledger tr > td:first-child { background-color: white; } {% else %} {% if dat_line.is_intro %} - + {{dat_line.booking.target}} {% elif dat_line.error %} @@ -64,17 +71,20 @@ table.ledger tr > td:first-child { background-color: white; } {% else %} - + + {% endif %} {% endif %} - {% if dat_line.error and not raw %} + + {% if (not raw) and dat_line.error %} {% endif %} + {% endfor %}
[#][b]{{dat_line.booking.date}} + {{dat_line.booking.date}} + {{dat_line.comment}}{{dat_line.booking_line.account}} {{dat_line.comment}}{{dat_line.comment}} {{dat_line.comment}} 
{{dat_line.error}}
@@ -108,6 +118,7 @@ function taint() { {% endmacro %} + {% macro edit_bar(target, id) %} prev · next @@ -121,6 +132,14 @@ function taint() { {% endmacro %} + +{% macro tr_money_balance(amt, curr) %} + +{{amt}} +{{curr|truncate(4,true,"…")}} + +{% endmacro %} + {% macro booking_balance_account_with_children(node) %} {{node.name}}{% if node.children %}:{% endif %} @@ -153,6 +172,7 @@ function taint() { {% endmacro %} + {% macro booking_balance(valid, roots) %}
-- 2.30.2 From abfc3c1548a2ef88529231118c50a670e165287c Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 24 Feb 2025 13:19:52 +0100 Subject: [PATCH 09/16] In /ledger_structured view, hide gap lines except where reasonable. --- src/run.py | 11 +++++ src/templates/_macros.tmpl | 94 ++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/run.py b/src/run.py index e27a438..db54b77 100755 --- a/src/run.py +++ b/src/run.py @@ -130,6 +130,7 @@ class Account: class DatLine(Dictable): """Line of .dat file parsed into comments and machine-readable data.""" dictables = {'booking_line', 'code', 'comment', 'error', 'is_intro'} + prev_line_empty: bool def __init__(self, line: str) -> None: self.raw = line[:] @@ -560,6 +561,7 @@ class Server(PlomHttpServer): booking.recalc_prev_next(self.bookings) if booking: booking.gap_lines = gap_lines[:-1] + self._recalc_prev_line_empty() def save(self) -> None: """Save current state to ._path_dat.""" @@ -597,11 +599,20 @@ class Server(PlomHttpServer): """If .dat_lines different to those of last .load().""" return self._hash_dat_lines() != self.last_save_hash + def _recalc_prev_line_empty(self) -> None: + prev_line = None + for line in self.dat_lines: + line.prev_line_empty = False + if prev_line: + line.prev_line_empty = not prev_line.code + prev_line.comment + prev_line = line + def _recalc_dat_lines(self) -> None: self.dat_lines = self.initial_gap_lines[:] for booking in self.bookings: self.dat_lines += booking.booked_lines self.dat_lines += booking.gap_lines + self._recalc_prev_line_empty() def _move_booking(self, idx_from, idx_to) -> None: moving = self.bookings[idx_from] diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index a1a2764..614a7fa 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -32,59 +32,65 @@ table.ledger tr > td:first-child { background-color: white; }
{% for dat_line in dat_lines %} - - - - {% if dat_line.is_intro %} - [#] - {{ table_dat_lines_action_button(dat_line, "move", "up", "^", dat_line.booking.can_move(1)) }} - {% elif dat_line.booking_line.idx == 1 %} - [b] - {{ table_dat_lines_action_button(dat_line, "move", "down", "v", dat_line.booking.can_move(0)) }} - {% elif dat_line.booking_line.idx == 2 %} - {{ table_dat_lines_action_button(dat_line, "copy", "here", "c") }} - {{ table_dat_lines_action_button(dat_line, "copy", "to_end", "C") }} - {% endif %} - + {% if raw or dat_line.code or dat_line.comment %} + + {% if (not raw) and dat_line.prev_line_empty %} + + {% endif %} + - {% if raw %} - + {% if dat_line.is_intro %} - {{dat_line.raw_nbsp|safe}} - {% else %} - {{dat_line.raw_nbsp|safe}} + [#] + {{ table_dat_lines_action_button(dat_line, "move", "up", "^", dat_line.booking.can_move(1)) }} + {% elif dat_line.booking_line.idx == 1 %} + [b] + {{ table_dat_lines_action_button(dat_line, "move", "down", "v", dat_line.booking.can_move(0)) }} + {% elif dat_line.booking_line.idx == 2 %} + {{ table_dat_lines_action_button(dat_line, "copy", "here", "c") }} + {{ table_dat_lines_action_button(dat_line, "copy", "to_end", "C") }} {% endif %} - {% else %} - {% if dat_line.is_intro %} - - {{dat_line.booking.target}} - - {% elif dat_line.error %} - - - {% elif dat_line.booking_line %} - - - - {% else %} - - + {% if dat_line.is_intro %} + + {{dat_line.booking.target}} + + {% elif dat_line.error %} + + + {% elif dat_line.booking_line %} + + + + + {% else %} + + + {% endif %} {% endif %} - {% endif %} - - - {% if (not raw) and dat_line.error %} - - - - - {% endif %} + {% if (not raw) and dat_line.error %} + + + + + + {% endif %} + + {% endif %} {% endfor %}
 
- {{dat_line.booking.date}} + + {% if raw %} + + {% if dat_line.is_intro %} + {{dat_line.raw_nbsp|safe}} + {% else %} + {{dat_line.raw_nbsp|safe}} + {% endif %} {{dat_line.comment}}{{dat_line.code}}{{dat_line.comment}}{{dat_line.booking_line.amount_short}}{{dat_line.booking_line.currency|truncate(4,true,"…")}}{{dat_line.booking_line.account}}{{dat_line.comment}}{{dat_line.comment}}  + {{dat_line.booking.date}} + {{dat_line.comment}}{{dat_line.code}}{{dat_line.comment}}{{dat_line.booking_line.amount_short}}{{dat_line.booking_line.currency|truncate(4,true,"…")}}{{dat_line.booking_line.account}}{{dat_line.comment}}{{dat_line.comment}} 
{{dat_line.error}}
{{dat_line.error}}
-- 2.30.2 From 1b3271d71d2bc98585e6d15af7961dad42c2145e Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 24 Feb 2025 13:38:46 +0100 Subject: [PATCH 10/16] Hide ;def comments in /ledger_structured. --- src/run.py | 31 ++++++++++++++++++++----------- src/templates/_macros.tmpl | 10 +++++----- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/run.py b/src/run.py index db54b77..8c26685 100755 --- a/src/run.py +++ b/src/run.py @@ -138,6 +138,12 @@ class DatLine(Dictable): self.comment = halves[1] if len(halves) > 1 else '' self.code = halves[0] self.booking_line: Optional[BookingLine] = None + self.hide_comment_in_ledger = False + + @property + def comment_in_ledger(self) -> str: + """What to show in structured ledger view (as per .hide_comment…).""" + return '' if self.hide_comment_in_ledger else self.comment @property def is_intro(self) -> bool: @@ -548,15 +554,16 @@ class Server(PlomHttpServer): booked_lines.clear() gap_lines += [dat_line] self.paths_to_descs = {} - for comment in [dl.comment for dl in self.dat_lines if dl.comment]: - if comment.startswith(PREFIX_DEF): - parts = [part.strip() for part - in comment[len(PREFIX_DEF):].split(';')] - first_part_parts = parts[0].split(maxsplit=1) - account_name = first_part_parts[0] - desc = first_part_parts[1] if len(first_part_parts) > 1 else '' - if desc: - self.paths_to_descs[account_name] = desc + for dat_line in [dl for dl in self.dat_lines + if dl.comment.startswith(PREFIX_DEF)]: + parts = [part.strip() for part + in dat_line.comment[len(PREFIX_DEF):].split(';')] + first_part_parts = parts[0].split(maxsplit=1) + account_name = first_part_parts[0] + desc = first_part_parts[1] if len(first_part_parts) > 1 else '' + if desc: + self.paths_to_descs[account_name] = desc + dat_line.hide_comment_in_ledger = True for booking in self.bookings: booking.recalc_prev_next(self.bookings) if booking: @@ -604,8 +611,10 @@ class Server(PlomHttpServer): for line in self.dat_lines: line.prev_line_empty = False if prev_line: - line.prev_line_empty = not prev_line.code + prev_line.comment - prev_line = line + line.prev_line_empty = not (prev_line.code + + prev_line.comment_in_ledger) + if prev_line or line.code + line.comment_in_ledger: # jump over + prev_line = line # empty start def _recalc_dat_lines(self) -> None: self.dat_lines = self.initial_gap_lines[:] diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index 614a7fa..a3187c9 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -32,7 +32,7 @@ table.ledger tr > td:first-child { background-color: white; }
{% for dat_line in dat_lines %} - {% if raw or dat_line.code or dat_line.comment %} + {% if raw or dat_line.code or dat_line.comment_in_ledger %} {% if (not raw) and dat_line.prev_line_empty %} @@ -66,18 +66,18 @@ table.ledger tr > td:first-child { background-color: white; } {{dat_line.booking.date}}{{dat_line.booking.target}} - + {% elif dat_line.error %} - + {% elif dat_line.booking_line %} - + {% else %} - + {% endif %} {% endif %} -- 2.30.2 From b3ecd628e2ad3f3134f6df04c9601faa111c49bd Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Wed, 26 Feb 2025 17:25:58 +0100 Subject: [PATCH 11/16] In /edit_structured disable replace button if un-applied changes. --- src/templates/_macros.tmpl | 26 +++++++++++++++----------- src/templates/edit_structured.tmpl | 6 +++--- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index a3187c9..35a4173 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -101,23 +101,27 @@ table.ledger tr > td:first-child { background-color: white; } function taint() { // activate buttons "apply", "revert" Array.from(document.getElementsByClassName("enable_on_change")).forEach((el) => { - el.disabled = false; + el.disabled = false; }); // deactivate Booking links - Array.from(document.getElementsByClassName("disable_on_change")).forEach((span) => { - let links_text = ''; - Array.from(span.childNodes).forEach((node) => { - links_text += node.textContent + ' '; - }); - span.innerHTML = ''; - const del = document.createElement("del"); - span.appendChild(del); - del.textContent = links_text; + Array.from(document.getElementsByClassName("disable_on_change")).forEach((el) => { + if (el.tagName == 'span') { + let links_text = ''; + Array.from(el.childNodes).forEach((node) => { + links_text += node.textContent + ' '; + }); + el.innerHTML = ''; + const del = document.createElement("del"); + el.appendChild(del); + del.textContent = links_text; + } else if (el.type == "button") { + el.disabled = true; + } }); // remove oninput handlers no longer needed (since we only ever go one way) ['input', 'textarea'].forEach((tag_name) => { Array.from(document.getElementsByTagName(tag_name)).forEach((el) => { - el.oninput = null; + el.oninput = null; }); }); } diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index 298510c..de2a226 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -147,8 +147,8 @@ function update_form() { table.appendChild(tr); const td = add_td(tr, 5); add_button(td, 'add line', false, function() { - new_line = {error: '', comment: '', booking_line: {account: '', amount: '', currency: ''}}; - dat_lines.push(new_line); + new_line = {error: '', comment: '', booking_line: {account: '', amount: '', currency: ''}}; + dat_lines.push(new_line); }); // make all rows alternate background color for better readability @@ -182,7 +182,7 @@ window.onload = update_form; {% block content %} {{ macros.edit_bar("raw", id) }} - + from to -- 2.30.2 From 3af2e382884ebca4f7f7e0a1c22039c86e71a6d0 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Wed, 26 Feb 2025 17:37:37 +0100 Subject: [PATCH 12/16] Add "mirror" button to /edit_structured. --- src/templates/edit_structured.tmpl | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index de2a226..c3431d3 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -175,6 +175,26 @@ function replace() { update_form(); } +function mirror() { + dat_lines.slice(1).forEach((dat_line) => { + let inverted_amount = `-${dat_line.booking_line.amount}`; + if (inverted_amount.startsWith('--')) { + inverted_amount = inverted_amount.slice(2); + } + dat_lines.push({ + error: '', + comment: '', + booking_line: { + account: '?', + amount: inverted_amount, + currency: dat_line.booking_line.currency + } + }); + }) + taint(); + update_form(); +} + window.onload = update_form; {% endblock %} @@ -182,6 +202,8 @@ window.onload = update_form; {% block content %} {{ macros.edit_bar("raw", id) }} + +| from -- 2.30.2 From 783cdc346dc43a90db342599497d4ae20f789fdc Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Wed, 26 Feb 2025 17:43:53 +0100 Subject: [PATCH 13/16] Fix /edit_structured replacement ignoring date line. --- src/templates/edit_structured.tmpl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index c3431d3..510ca84 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -161,15 +161,15 @@ function replace() { const from = document.getElementById("replace_from").value; const to = document.getElementById("replace_to").value; dat_lines.forEach((dat_line) => { - dat_line.comment = dat_line.comment.replaceAll(from, to); - if ('code' in dat_line) { - dat_line.code = dat_line.code.replaceAll(from, to); - } - ['account', 'amount', 'currency'].forEach((key) => { - if (key in dat_line.booking_line) { - dat_line.booking_line[key] = dat_line.booking_line[key].replaceAll(from, to); + dat_line.comment = dat_line.comment.replaceAll(from, to); + if ('code' in dat_line) { + dat_line.code = dat_line.code.replaceAll(from, to); } - }); + ['date', 'target', 'account', 'amount', 'currency'].forEach((key) => { + if (key in dat_line.booking_line) { + dat_line.booking_line[key] = dat_line.booking_line[key].replaceAll(from, to); + } + }); }); taint(); update_form(); -- 2.30.2 From 5be4b8789cce02024984f5780f0c928cbe252fd1 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Sat, 1 Mar 2025 02:44:56 +0100 Subject: [PATCH 14/16] In /edit_structured view, put line movement buttons to left side. --- src/templates/edit_structured.tmpl | 37 ++++++++++++++++++------------ 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index 510ca84..70df624 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -93,11 +93,27 @@ function update_form() { function add_td_input(name, value, size=20, colspan=1) { return add_input(setup_input_td(tr, colspan), name, value, size); } + + // movement buttons + const td_btns_updown = add_td(tr); + if (i > 0) { + [{label: '^', earlier_idx: i-1, enabled: i > 1}, + {label: 'v', earlier_idx: i, enabled: i && i+1 < dat_lines.length} + ].forEach((kwargs) => { + add_button(td_btns_updown, kwargs.label, ! kwargs.enabled, function() { + const other_line = dat_lines[kwargs.earlier_idx]; + dat_lines.splice(kwargs.earlier_idx, 1); + dat_lines.splice(kwargs.earlier_idx + 1, 0, other_line); + }); + }); + } + + // actual input lines if (dat_line.is_intro) { const td = setup_input_td(tr, 3); const date_input = add_input(td, 'date', dat_line.booking_line.date, 10) date_input.classList.add('date_input'); - add_input(td, 'target', dat_line.booking_line.target, 35) + add_input(td, 'target', dat_line.booking_line.target, 37) } else if (!dat_line.error) { // i.e. valid TransferLine const acc_input = add_td_input('account', dat_line.booking_line.account, 30); acc_input.setAttribute ('list', 'all_accounts'); @@ -116,20 +132,11 @@ function update_form() { } add_td_input('comment', dat_line.comment, 40); - // add action buttons, with "delete" after some safety distance - const td_btns = add_td(tr); - add_button(td_btns, '^', i > 1 ? false : true, function() { - const prev_line = dat_lines[i-1]; - dat_lines.splice(i-1, 1); - dat_lines.splice(i, 0, prev_line); - }); - add_button(td_btns, 'v', (i && i+1 < dat_lines.length) ? false : true, function() { - const next_line = dat_lines[i]; - dat_lines.splice(i, 1); - dat_lines.splice(i+1, 0, next_line); - }); - td_btns.appendChild(document.createTextNode(' · · · ')) - add_button(td_btns, 'delete', i > 0 ? false : true, function() { dat_lines.splice(i, 1); }); + // delete button + td_del = add_td(tr); + if (i > 0) { + add_button(td_del, 'delete', i > 0 ? false : true, function() { dat_lines.splice(i, 1); }); + } // add error explanation row if necessary if (dat_line.error) { -- 2.30.2 From f7685622568bed7c7bf3e08982aaefa5ef2d4b91 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 3 Mar 2025 02:26:52 +0100 Subject: [PATCH 15/16] In /edit_structured, add "add line" buttons for all lines. --- src/templates/edit_structured.tmpl | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/templates/edit_structured.tmpl b/src/templates/edit_structured.tmpl index 70df624..959574c 100644 --- a/src/templates/edit_structured.tmpl +++ b/src/templates/edit_structured.tmpl @@ -132,10 +132,16 @@ function update_form() { } add_td_input('comment', dat_line.comment, 40); - // delete button - td_del = add_td(tr); + // line deletion and addition buttons + td_add_del = add_td(tr); + add_button(td_add_del, 'add new', false, function() { + new_line = {error: '', comment: '', booking_line: {account: '', amount: '', currency: ''}}; + dat_lines.splice(i + 1, 0, new_line); + }); if (i > 0) { - add_button(td_del, 'delete', i > 0 ? false : true, function() { dat_lines.splice(i, 1); }); + add_button(td_add_del, 'delete', i > 0 ? false : true, function() { + dat_lines.splice(i, 1); + }); } // add error explanation row if necessary @@ -149,15 +155,6 @@ function update_form() { } } - // add "add line" row - const tr = document.createElement("tr"); - table.appendChild(tr); - const td = add_td(tr, 5); - add_button(td, 'add line', false, function() { - new_line = {error: '', comment: '', booking_line: {account: '', amount: '', currency: ''}}; - dat_lines.push(new_line); - }); - // make all rows alternate background color for better readability Array.from(table.rows).forEach((tr) => { tr.classList.add('alternating'); -- 2.30.2 From 9fe8020856ad97615d8c6499a94e1810acc57047 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 3 Mar 2025 02:33:26 +0100 Subject: [PATCH 16/16] Fix broken link deactivation in /edit_structured. --- src/templates/_macros.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index 35a4173..f6495aa 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -105,7 +105,7 @@ function taint() { }); // deactivate Booking links Array.from(document.getElementsByClassName("disable_on_change")).forEach((el) => { - if (el.tagName == 'span') { + if (el.tagName == 'SPAN') { let links_text = ''; Array.from(el.childNodes).forEach((node) => { links_text += node.textContent + ' '; @@ -119,7 +119,7 @@ function taint() { } }); // remove oninput handlers no longer needed (since we only ever go one way) - ['input', 'textarea'].forEach((tag_name) => { + ['INPUT', 'TEXTAREA'].forEach((tag_name) => { Array.from(document.getElementsByTagName(tag_name)).forEach((el) => { el.oninput = null; }); -- 2.30.2
 
{{dat_line.comment}}{{dat_line.comment_in_ledger}}{{dat_line.code}}{{dat_line.comment}}{{dat_line.comment_in_ledger}}{{dat_line.booking_line.amount_short}} {{dat_line.booking_line.currency|truncate(4,true,"…")}} {{dat_line.booking_line.account}}{{dat_line.comment}}{{dat_line.comment_in_ledger}}{{dat_line.comment}} {{dat_line.comment_in_ledger}}