Skip to content

Follow-ups to the mobile rework: caching, dialogs, time zones, ownership checks, cleanup - #4

Merged
codeling merged 16 commits into
mainfrom
claude/nice-lovelace-rmoc8c
Sep 30, 2026
Merged

codeling merged 16 commits into
mainfrom
claude/nice-lovelace-rmoc8c

Conversation

@codeling

@codeling codeling commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #3:

  • Append modification time to local JS/CSS URLs: assetUrl() in todo-core.php adds ?v=<filemtime>, so changed files are fetched again. This includes the vendor/ files.
  • Keep dialogs within the window on resize: after rotating a phone, an open dialog stuck out of the screen. Open dialogs are now resized and re-centered, with a CSS max-width as fallback.

Open issues from the previous review

  1. Statistics page:
  2. Info only in tooltips: the modify dialog now shows the creation and completion date. Recurrence and notes were already fields there.
  3. Start date on phones: narrow screens show start → due for open todos.
  4. Time zones:
    • Start/due dates were parsed as UTC midnight and shown in local time, so west of UTC they appeared, and were saved back, one day early.
    • New parseDay() reads them as local calendar days. Creation/completion timestamps are still read as UTC.
  5. enter() no longer sends recurrenceAnchor=NaN.
  6. The load-more links no longer follow href="#".
  7. Server messages:
  8. Cleanup:
    • Removes unused language strings: the old datepicker texts and texts only the old mobile version used.
    • Adds missing keys the code used, which showed as raw key names: DOTODAY, EDITED_TAG_SUCCESSFUL, and MERGE_TAG_SUCCESSFUL (was named MERGE_SUCCESSFUL).
    • Removes the unused images/ directory.
  9. Ownership checks:
    • Queries taking a list or todo id check that it belongs to $curUserID, and reply "access denied" otherwise. They are written as prepared statements, like the rest of Security fixes: SQL injection, CSRF, XSS, access control; npm-managed JS libs #5.
    • The affected queries: query-todos, query-tags, enter, update (including moving to another list), complete, trash, reactivate-one, empty-trash.
    • There is still no login; $curUserID stays the default user 0. Tags are global, so the tag queries are not restricted.
  10. JS files: todo-common.js and todo-desktop.js are merged into todo.js, and the unused emptyModifyForm() is removed.

Also found while testing:

  • sql/install.sql: it created no list 0, which todo.list_id defaults to, so a fresh install couldn't add todos. The insert now also names its columns.

Merge with main (#5)

The conflicts are resolved in a merge commit.

  • The query scripts use main's code (prepared statements, POST + CSRF token, generic database errors), with this PR's translations and ownership checks on top.
  • main's changes to todo-desktop.js (HTML escaping, POST for the tag requests) are ported into todo.js.

Testing

After the merge, tested against a real MariaDB 10.11 database created from the merged sql/install.sql:

  • With curl (session cookie + CSRF token), each query endpoint for own and foreign lists/todos:
    • Access checks are enforced.
    • Validation, version-conflict, CSRF and GET-not-allowed messages are correct, in English and German.
  • In headless Chromium with the real backend, desktop (Europe/Berlin) and phone at 390px (America/New_York):
    • Adding, editing, completing, trashing and emptying the trash all work.
    • The tag and log dialogs fit on the phone screen.
    • Dates are identical in both time zones and don't shift when saved.
    • HTML entered in a todo is shown as text.
    • No JS errors, console/CSP errors or failed requests.
  • php -l passes on all changed PHP files.

🤖 Generated with Claude Code

https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN

Browsers kept using cached versions of todo-common.js, todo.css etc.
after an update, so fixes only showed up after a forced reload (e.g. a
newly added todo showing no start/due date until reload, or the modify
dialog being too wide on mobile). With ?v=<mtime> the new files are
loaded as soon as they change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
The dialog width was only adapted when opening a dialog; after rotating
a phone (or resizing the window) an open dialog could stick out of the
screen. Open dialogs are now resized and re-centered on window resize,
and a CSS max-width serves as fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
- lang.php and todo-core.php now work from any working directory, so
  the query scripts can use the language files; all hard-coded (partly
  German) messages in queries/*.php are now translated
- queries taking a list or todo id check that it belongs to the current
  user ($curUserID, still fixed to the default user as there is no
  login yet) and reply "access denied" otherwise
- query-lists.php uses $curUserID instead of a hard-coded 0
- reactivate-one.php used the query result instead of the affected row
  count, so it always reported success

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
The settings INSERT had no VALUES clause and failed. There was also no
list 0, which todo.list_id defaults to and the frontend starts with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
- viewport meta, charts scroll horizontally on narrow screens
- the optional site navigation was included with a short open tag
  (disabled by default), so it was printed as text; it is now included
  properly if the file exists
- remove the commented-out references to files that no longer exist
- only count todos in lists of the current user

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
Start and due dates are calendar days, but were parsed as UTC midnight
and formatted in local time, so west of UTC they were shown (and saved
back from the modify dialog) one day early. They are now parsed as
local days; creation/completion timestamps are still UTC.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
Clicking them added "#" to the URL and jumped to the top of the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
- remove the texts of the removed jQuery UI datepicker and the texts
  only used by the removed mobile version (CANCEL, LOG, NEW_TODO,
  REFRESH, TOGGLE)
- add missing DOTODAY and EDITED_TAG_SUCCESSFUL, rename MERGE_SUCCESSFUL
  to MERGE_TAG_SUCCESSFUL as used in the code (the raw keys were shown)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
All icons are inlined into todo.css as data URIs; the last reference
(calendar.svg for the jQuery UI datepicker) is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
They were only available as a tooltip on the todo, which touch devices
can't show. Recurrence and notes are already fields in the dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
Without a separate mobile version, the split into common and desktop
code no longer has a purpose. Also remove emptyModifyForm(), which was
only used by the mobile version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
@codeling codeling changed the title Load new JS/CSS after updates; keep dialogs on screen Follow-ups to the mobile rework: caching, dialogs, time zones, ownership checks, cleanup Sep 28, 2026
Comment thread todo.js Fixed
Comment thread todo.js Fixed
var tagbase = 'tag_todo_tags_';
for (var i=0; i<filtered.length; i++) {
var line = getTodoTitleHtml(filtered[i], i, tagbase, 'todo', 'div', false);
$('#tag_todo_table').append(line);
Conflict resolution:
- query scripts: main's prepared statements, POST+CSRF and generic
  database errors, with this branch's translated messages and list/todo
  ownership checks on top (requireOwnList/requireOwnTodo now use dbExec);
  main's new validation messages and the session/database error messages
  are translated as well
- todo.js: main's todo-desktop.js changes (HTML escaping, POST for tag
  requests) ported into the merged file
- index.php: vendor/ paths from main, all local JS/CSS via assetUrl()
- statistik.php: keep main's removal of the external navigation include
- install.sql: explicit column list plus the default list 0
- todo.css, todo-core.php: keep both sides

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
getRecurrenceString() reads the option label from the DOM (.text()),
which was inserted unescaped into the title attribute (CodeQL
js/xss-through-dom). The label comes from the language file, so this
was not exploitable, but it is now escaped like the other values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019bDAqsvVCaQoaCKwFYcnDN
@codeling
codeling merged commit f9eb4f5 into main Sep 30, 2026
4 checks passed
@codeling
codeling deleted the claude/nice-lovelace-rmoc8c branch September 30, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants