Skip to content

feat(messages.html): user badges, contact search, auto-scroll to latest#946

Merged
PythonSmall-Q merged 8 commits intofeature/messages-webuifrom
copilot/sub-pr-944-again
Mar 15, 2026
Merged

feat(messages.html): user badges, contact search, auto-scroll to latest#946
PythonSmall-Q merged 8 commits intofeature/messages-webuifrom
copilot/sub-pr-944-again

Conversation

Copy link
Contributor

Copilot AI commented Mar 15, 2026

Adds three UX improvements to the messages WebUI: user badge display (mirroring XMOJ.user.js), a local contact search box, and reliable auto-scroll to the latest message.

User badges

  • getUserBadge(username) — calls apiCall('GetBadge', { UserID }), caches result 24 h in localStorage under UserScript-User-{u}-Badge-{BackgroundColor|Color|Content|LastUpdateTime} (same keys as XMOJ.user.js)
  • loadBadgesForContainer(container) — single DOM pass using a Map keyed by username; for each unique user fires one getUserBadge() call, then inserts a Bootstrap badge <span> after every matching .user-info-btn via insertAdjacentElement
  • Called after initUserButtons in both renderMailList and loadThread; also rendered in the user-info modal title
  • Duplicate-injection guard via user-badge class check on nextElementSibling

Contact search

  • mailListCache stores the last GetMailList response
  • renderMailList(query) filters OtherUser case-insensitively; no API call
  • <input type="search" id="list-search"> above the table drives filtering on input event
  • Back button clears the input and calls renderMailList('') before refreshing, so returning to the list always shows all contacts

Auto-scroll

  • Replaced immediate scrollTop = scrollHeight with requestAnimationFrame(…) so layout is computed before reading scrollHeight
  • Added img.addEventListener('load', …) inside thread render to re-scroll as images load in

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.


Summary by cubic

Adds a new messages.html WebUI with local contact search and user badges next to usernames. Fixes dark‑mode table colors and timestamp formatting, and improves scroll‑to‑latest behavior.

  • New Features

    • Show user badges next to usernames in lists and threads; cached for 24h via GetBadge.
    • Sender name opens a user info modal with a “View profile” link; zoomable images, paste‑to‑upload, auto‑resizing compose box, and device‑aware login defaults.
  • Bug Fixes

    • Correct timestamp units and show year for older messages; add dark‑mode overrides for .table-primary and remove table-light headers so unread rows render correctly.
    • Reliable auto‑scroll to the latest message using requestAnimationFrame and per‑image load handlers; clear search on Back to restore the full contact list.

Written for commit d4f7bb1. Summary will update on new commits.

- Desktop/mobile login tab priority: bookmarklet on desktop (pointer: fine), session on mobile
- Replace sender name links with Bootstrap popovers showing user info popup
- Image zoom: cursor: zoom-in/zoom-out, title tooltip on images
- Global Ctrl+V paste handler for images anywhere in thread view
- Auto-resize compose textarea as user types

Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 15, 2026

Deploying xmoj-script-dev-channel with  Cloudflare Pages  Cloudflare Pages

Latest commit: d4f7bb1
Status: ✅  Deploy successful!
Preview URL: https://63600953.xmoj-script-dev-channel.pages.dev
Branch Preview URL: https://copilot-sub-pr-944-again.xmoj-script-dev-channel.pages.dev

View logs

Copilot AI changed the title [WIP] [752] Add messages.html WebUI for short messages feat(messages.html): UX improvements — device-aware login, user info popover, image zoom, global paste upload Mar 15, 2026
Copilot AI requested a review from PythonSmall-Q March 15, 2026 09:08
Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Copilot AI changed the title feat(messages.html): UX improvements — device-aware login, user info popover, image zoom, global paste upload fix(messages.html): show year in timestamps for cross-year messages Mar 15, 2026
Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Copilot AI changed the title fix(messages.html): show year in timestamps for cross-year messages fix(messages.html): fix two dark mode / timestamp display bugs Mar 15, 2026
…nfo modal

Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Copilot AI changed the title fix(messages.html): fix two dark mode / timestamp display bugs fix(messages.html): dark mode white row, year ~58000 display, user info modal Mar 15, 2026
@PythonSmall-Q
Copy link
Member

@copilot 访问xmoj.tech的时候origin设置为xmoj.tech

…in userinfo fetch

Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 15, 2026

@copilot 访问xmoj.tech的时候origin设置为xmoj.tech

Done in 7678bd5. The fetch() call to userinfo.php now includes:

  • referrer: XMOJ_BASE + '/' — sets the Referer header to https://www.xmoj.tech/ so the server sees the request as originating from xmoj.tech
  • credentials: 'include' — sends the browser's xmoj.tech session cookies along with the request

Note: the browser-controlled Origin header cannot be overridden by JavaScript; only Referer is settable this way. If the server performs strict CORS Origin validation, a backend CORS header allowlist would be needed on the xmoj.tech side.

Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Copilot AI changed the title fix(messages.html): dark mode white row, year ~58000 display, user info modal feat(messages.html): local contact search + user badge loading Mar 15, 2026
…ck + auto-scroll fix

Co-authored-by: PythonSmall-Q <106425289+PythonSmall-Q@users.noreply.github.com>
Copilot AI changed the title feat(messages.html): local contact search + user badge loading feat(messages.html): user badges, contact search, auto-scroll to latest Mar 15, 2026
@PythonSmall-Q PythonSmall-Q marked this pull request as ready for review March 15, 2026 09:57
Copilot AI review requested due to automatic review settings March 15, 2026 09:57
@PythonSmall-Q PythonSmall-Q merged commit 7a5dbe5 into feature/messages-webui Mar 15, 2026
3 checks passed
@PythonSmall-Q PythonSmall-Q deleted the copilot/sub-pr-944-again branch March 15, 2026 09:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the messages.html WebUI user experience by adding user badges and a user-info modal, enabling local (no-API) contact search, and making “scroll to latest” more reliable during thread rendering.

Changes:

  • Add clickable usernames that open a user-info modal and display cached user badges (via GetBadge) next to usernames.
  • Add a local contact search input backed by a cached GetMailList response to filter without additional API calls.
  • Improve auto-scroll behavior using requestAnimationFrame and re-scrolling on image load; adjust table header styling for dark mode.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

function formatTime(ts) {
if (!ts) return '';
var d = new Date(ts * 1000);
var d = new Date(ts);
Comment on lines +502 to +525
async function showUserInfo(username) {
var title = document.getElementById('user-info-modal-title');
var body = document.getElementById('user-info-modal-body');
var profileLink = document.getElementById('user-info-profile-link');
var profileUrl = XMOJ_BASE + '/userinfo.php?user=' + encodeURIComponent(username);

title.textContent = username;
profileLink.href = profileUrl;
body.innerHTML = '<div class="text-center py-3"><span class="spinner-border spinner-border-sm me-2"></span>加载中…</div>';
userInfoModalBS.show();

var results = await Promise.allSettled([
fetch(profileUrl, { referrer: XMOJ_BASE + '/', credentials: 'include' })
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); }),
getUserBadge(username)
]);

// ── Badge (render into title) ───────────────────────────────────────────
var badge = results[1].status === 'fulfilled' ? results[1].value : null;
if (badge && badge.Content) {
title.innerHTML = escapeHtml(username) +
' <span class="badge ms-2" style="background-color:' + escapeHtml(badge.BackgroundColor) +
';color:' + escapeHtml(badge.Color) + '">' + escapeHtml(badge.Content) + '</span>';
}
Comment on lines +550 to +560
var submitEl = doc.querySelector('#statics > tbody > tr:nth-child(3) > td:nth-child(2)');
var acceptEl = doc.querySelector('#statics > tbody > tr:nth-child(4) > td:nth-child(2)');
var submitCount = submitEl ? (parseInt(submitEl.textContent.trim()) || 0) : 0;
var acceptCount = acceptEl ? (parseInt(acceptEl.textContent.trim()) || 0) : 0;
var rating = submitCount > 0 ? ((acceptCount / submitCount) * 1000).toFixed(1) : '—';

var tbodyRows = doc.querySelectorAll('#statics > tbody > tr');
var email = '';
if (tbodyRows.length > 0) {
var lastCells = tbodyRows[tbodyRows.length - 1].querySelectorAll('td');
if (lastCells.length >= 2) email = lastCells[1].textContent.trim();
Comment on lines +761 to +765
// Re-scroll after each image loads so the bottom stays in view
if (atBottom) {
img.addEventListener('load', function() {
scrollEl.scrollTop = scrollEl.scrollHeight;
});
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="messages.html">

<violation number="1" location="messages.html:513">
P2: Out-of-order `showUserInfo()` responses can overwrite the profile that is currently open.</violation>

<violation number="2" location="messages.html:660">
P2: Scope or clear `mailListCache` on session changes; otherwise search can briefly expose the previous user's inbox after re-login.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +513 to +517
var results = await Promise.allSettled([
fetch(profileUrl, { referrer: XMOJ_BASE + '/', credentials: 'include' })
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); }),
getUserBadge(username)
]);
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Out-of-order showUserInfo() responses can overwrite the profile that is currently open.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At messages.html, line 513:

<comment>Out-of-order `showUserInfo()` responses can overwrite the profile that is currently open.</comment>

<file context>
@@ -397,18 +434,153 @@ <h5 class="mb-0 flex-grow-1" id="thread-title">与 … 的对话</h5>
+    body.innerHTML = '<div class="text-center py-3"><span class="spinner-border spinner-border-sm me-2"></span>加载中…</div>';
+    userInfoModalBS.show();
+
+    var results = await Promise.allSettled([
+        fetch(profileUrl, { referrer: XMOJ_BASE + '/', credentials: 'include' })
+            .then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); }),
</file context>
Suggested change
var results = await Promise.allSettled([
fetch(profileUrl, { referrer: XMOJ_BASE + '/', credentials: 'include' })
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); }),
getUserBadge(username)
]);
var requestId = String(Date.now()) + Math.random();
title.dataset.requestId = requestId;
var results = await Promise.allSettled([
fetch(profileUrl, { referrer: XMOJ_BASE + '/', credentials: 'include' })
.then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.text(); }),
getUserBadge(username)
]);
if (title.dataset.requestId !== requestId) return;
Fix with Cubic

}

// ── Mail List ──────────────────────────────────────────────────────────────
function renderMailList(query) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Scope or clear mailListCache on session changes; otherwise search can briefly expose the previous user's inbox after re-login.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At messages.html, line 660:

<comment>Scope or clear `mailListCache` on session changes; otherwise search can briefly expose the previous user's inbox after re-login.</comment>

<file context>
@@ -485,35 +657,53 @@ <h5 class="mb-0 flex-grow-1" id="thread-title">与 … 的对话</h5>
 }
 
 // ── Mail List ──────────────────────────────────────────────────────────────
+function renderMailList(query) {
+    var tbody = document.getElementById('list-tbody');
+    var q = query ? query.trim().toLowerCase() : '';
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants