Skip to content

refactor userscript structure #882

Closed
boomzero wants to merge 41 commits intodevfrom
claude/refactor-userscript-structure-011CUxWM4EozUNd9os4Da49N
Closed

refactor userscript structure #882
boomzero wants to merge 41 commits intodevfrom
claude/refactor-userscript-structure-011CUxWM4EozUNd9os4Da49N

Conversation

@boomzero
Copy link
Member

@boomzero boomzero commented Nov 10, 2025

What does this PR aim to accomplish?:

Adds: Bundler

How does this PR accomplish the above?:

Separates the code into different modules.
This PR cost $27 in claude credits


By submitting this pull request, I confirm the following:

  1. I have read and understood the contributor's guide, as well as this entire template. I understand which branch to base my commits and Pull Requests against.
  2. I have commented on my proposed changes within the code and I have tested my changes.
  3. I am willing to help maintain this change if there are issues with it later.
  4. It is compatible with the GNU General Public License v3.0
  5. I have squashed any insignificant commits. (git rebase)
  6. I have checked that another pull request for this purpose does not exist.
  7. I have considered and confirmed that this submission will be valuable to others.
  8. I accept that this submission may not be used, and the pull request can be closed at the will of the maintainer.
  9. I give this submission freely and claim no ownership to its content.

  • I have read the above and my PR is ready for review. Check this box to confirm

boomzero and others added 22 commits February 8, 2025 09:15
Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
(cherry picked from commit 07d7590)

Update feature.yml

Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
(cherry picked from commit 1a99430)

Update docs.yml

Signed-off-by: Zhu Chenrui <boomzero_zcr@outlook.com>
(cherry picked from commit 6017bcf)
This commit refactors the XMOJ-Script from a single 5000-line file into
a modular structure using Rollup bundler for better maintainability.

Changes:
- Added Rollup bundler configuration
- Separated code into modules:
  - src/core/: Core application logic and configuration
  - src/utils/: Utility functions (HTML, time, format, API, etc.)
  - src/features/: Feature modules (to be expanded)
- Created main entry point (src/main.js)
- Updated package.json with build scripts
- Added README_REFACTORING.md with structure documentation

All original functionality is preserved. The build output (dist/XMOJ.user.js)
maintains the same userscript header and behavior.

Build instructions:
- npm install (install dependencies)
- npm run build (build once)
- npm run watch (watch and rebuild)

Future work: Individual features can now be extracted into separate modules
under src/features/ for better organization.
This commit demonstrates the feature extraction pattern by extracting
5 major features into separate, maintainable modules:

Extracted Features:
- AutoLogin: Automatic redirection to login page
- Discussion: Complete forum system with 777 lines of code
- CopySamples: Fix copy functionality for test samples
- CompareSource: Side-by-side code comparison with diff
- RemoveUseless: Remove unwanted page elements

Structure Added:
- src/features/auto-login.js
- src/features/discussion.js
- src/features/copy-samples.js
- src/features/compare-source.js
- src/features/remove-useless.js
- src/features/index.js (feature loader)

Each feature module follows the pattern:
- Imports UtilityEnabled from config
- Exports an init() function
- Self-checks if enabled before executing
- Proper ES6 module structure

Updated Files:
- src/main.js: Added feature initialization
- README_REFACTORING.md: Added feature extraction documentation

Remaining Features:
36 features remain in bootstrap.js and can be extracted following
the same pattern. The infrastructure is in place for incremental
extraction.

Note: Features currently exist in both bootstrap.js and feature modules
for compatibility. Future work can remove duplicates from bootstrap.js.
This commit continues the feature extraction process by adding 6 new
feature modules, demonstrating the established extraction pattern:

New features extracted:
- ReplaceXM: Replaces "小明" references with "高老师"
- ReplaceYN: Replaces Y/N status indicators with symbols (✓/✗/⏳)
- AddAnimation: Adds CSS transitions to status and test-case elements
- AddColorText: Adds CSS classes for colored text (red, green, blue)
- SavePassword: Automatically saves and fills login credentials
- RemoveAlerts: Removes redundant alerts and warnings

All features follow the established pattern with:
- init() function for initialization
- UtilityEnabled() checks for feature flags
- Clear documentation of extracted code locations
- Self-contained, maintainable modules

Updated:
- src/features/index.js: Added imports and initialization for new features
- README_REFACTORING.md: Updated documentation with new features
- dist/XMOJ.user.js: Rebuilt with new features

Total extracted features: 11 (was 5)
Remaining features: 30 (was 36)
This commit continues feature extraction by adding 3 new feature modules:

New features extracted:
- ReplaceLinks: Replaces bracketed links with styled buttons
  - Transforms [<a href="...">text</a>] into styled button elements
- AutoO2: Automatically enables O2 optimization flag for code submissions
  - Auto-checks the O2 checkbox on problem submission pages
- Translate: Translates English text to Chinese throughout the site
  - Navbar translations
  - Problem set page form placeholders and headers
  - Contest page table headers

All features follow the established pattern with:
- init() function for initialization
- UtilityEnabled() checks for feature flags
- Page-specific logic where appropriate
- Error handling and logging

Updated:
- src/features/index.js: Added imports and initialization for new features
- README_REFACTORING.md: Updated documentation with new features
- dist/XMOJ.user.js: Rebuilt with new features (485KB, 6870 lines)

Total extracted features: 14 (was 11)
Remaining features: 27 (was 30)
…nAllProblem

This commit continues feature extraction by adding 4 utility feature modules:

New features extracted:
- AutoCountdown: Automatically updates countdown timers on the page
  - Updates timers with class "UpdateByJS" every second
  - Reloads page when countdown expires
  - Disables default clock on contest pages

- MoreSTD: Adds standard solution links to contest problem tables
  - Reorganizes contest problem table
  - Adds "标程" column with links to standard solutions

- ExportACCode: Exports all accepted code solutions as a ZIP file
  - Adds export button to user info page
  - Fetches AC code from export_ac_code.php
  - Uses JSZip library to create downloadable ZIP

- OpenAllProblem: Adds buttons to open all/unsolved problems
  - "打开全部题目" - Opens all contest problems in new tabs
  - "打开未解决题目" - Opens only unsolved problems

All features follow the established pattern with:
- init() function for initialization
- UtilityEnabled() checks for feature flags
- Page-specific logic and error handling

Updated:
- src/features/index.js: Added imports and initialization for new features
- README_REFACTORING.md: Updated documentation with new features
- dist/XMOJ.user.js: Rebuilt with new features (498KB, 7216 lines)

Total extracted features: 18 (was 14)
Remaining features: 23 (was 27)
This commit adds 2 additional feature modules:

New features extracted:
- DarkMode: Enables dark theme for the website
  - Sets Bootstrap theme attribute to "dark" or "light"
  - Used by 17 different locations for conditional styling
  - Exports isDarkMode() helper function for other features

- ImproveACRate: Adds a button to resubmit already-AC'd problems
  - Fetches user's AC problems from userinfo page
  - Displays current AC rate percentage
  - Resubmits 3 random AC'd problems to improve statistics
  - Uses existing AC code from status page

All features follow the established pattern with:
- init() function for initialization
- UtilityEnabled() checks for feature flags
- Page-specific logic and error handling

Updated:
- src/features/index.js: Added imports and initialization for new features
  - DarkMode initialized early (before other styling features)
- README_REFACTORING.md: Updated documentation with new features
- dist/XMOJ.user.js: Rebuilt with new features (506KB, 7388 lines)

Total extracted features: 20 (was 18)
Remaining features: 21 (was 23)
Copy link
Member

@langningchen langningchen left a comment

Choose a reason for hiding this comment

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

LGTM

This commit introduces a new page module system to better organize
page-specific styling and functionality that was scattered throughout
bootstrap.js. This significantly improves code maintainability by
separating concerns.

New page modules created:
- problem.js: Handles /problem.php page
  - Submit button fixes (dynamic selector handling)
  - Sample data card styling
  - IO file information extraction
  - Discussion button with unread badge
  - Custom page styling for code blocks

- contest.js: Handles /contest.php page
  - Contest list view with countdown timers
  - Running/upcoming/finished contest states
  - Contest view with problem list formatting
  - Time display formatting

- status.js: Handles /status.php page
  - Page title and cleanup
  - Foundation for future status page styling

- submit.js: Handles /submitpage.php page
  - Page title based on problem/contest
  - Foundation for future submit page styling

Page loader system:
- src/pages/index.js: Centralized page loader
- Routes pages based on location.pathname
- Passes context object with utilities to each page
- Integrates with main.js via window.load event
- Runs after bootstrap.js setup but provides cleaner organization

Benefits:
- Separates page-specific code from features
- Makes it easier to find and modify page styling
- Reduces bootstrap.js size over time
- Provides clear structure for adding more pages
- Better code organization and maintainability

Updated:
- src/main.js: Added page loader integration
- README_REFACTORING.md: Documented page module system
- dist/XMOJ.user.js: Rebuilt with page modules (524KB, 7901 lines)

Next steps:
- Continue extracting more page modules (login, userinfo, etc.)
- Move more styling from bootstrap.js to page modules
- Further reduce bootstrap.js size
This commit continues building out the page module system by extracting
5 additional page modules, improving code organization significantly.

New page modules:
- problemset.js: /problemset.php
  - Column width management
  - Improved search forms layout
  - Problem name caching in localStorage

- userinfo.js: /userinfo.php
  - User profile layout with avatar (Gravatar/Cravatar)
  - AC problems display in grid format
  - Badge management for admins (add/delete)
  - Last online time (async loading)
  - Translated table headers

- login.js: /loginpage.php
  - Bootstrap-styled login form
  - Foundation for login handling (LoginFailed feature)

- contestrank.js: /contestrank-oi.php and /contestrank-correct.php
  - Shared module for both OI and correct rankings
  - Medal badges for top rankings
  - Colored cells based on AC/WA status
  - Error count display
  - Auto-refresh support for OI rankings
  - Dark mode support for cell colors

Updated:
- src/pages/index.js: Added 5 new page routes (7 pathnames total)
- src/main.js: Enhanced page context with more utilities
  - Added GetUserInfo, GetUserBadge, GetUsernameHTML
  - Added GetRelativeTime, SmartAlert
  - Added IsAdmin flag
- README_REFACTORING.md: Documented all 8 page modules
- dist/XMOJ.user.js: Rebuilt (549KB, 8591 lines)

Benefits:
- Page-specific code is now well-organized and easy to find
- Clearer separation between features and page styling
- Each page module is self-contained and maintainable
- Context object provides necessary utilities to pages
- Bootstrap.js continues to shrink as code is extracted

Total page modules: 8 (was 4)
Total feature modules: 20
@boomzero boomzero added the frozen We are not going to fix this soon label Dec 7, 2025
@PythonSmall-Q
Copy link
Member

Let me have a look

@PythonSmall-Q PythonSmall-Q self-requested a review December 8, 2025 12:20
Updated Bootstrap and cdnjs versions in bootstrap.js to improve compatibility and security. Also includes fixes for tidytable and popover usability, adds username rendering for noticeboard, and improves ACM rank display.
Copy link
Member

@PythonSmall-Q PythonSmall-Q left a comment

Choose a reason for hiding this comment

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

LGTM

@hendragon-bot hendragon-bot bot added the user-script This issue or pull request is related to the main user script label Dec 10, 2025
@boomzero
Copy link
Member Author

boomzero commented Dec 11, 2025

Unfortunately, their are still bugs that remain to be fixed

@PythonSmall-Q PythonSmall-Q self-requested a review December 13, 2025 13:34
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

Copilot reviewed 51 out of 53 changed files in this pull request and generated 12 comments.


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

@@ -0,0 +1,256 @@
// Index page handler
import { UtilityEnabled } from '../core/config.js';
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Unused import UtilityEnabled.

Suggested change
import { UtilityEnabled } from '../core/config.js';

Copilot uses AI. Check for mistakes.
* @param {Object} context - Execution context
*/
export async function handleIndexPage(context) {
const { location, SearchParams, initTheme, marked } = context;
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Unused variable SearchParams.

Suggested change
const { location, SearchParams, initTheme, marked } = context;
const { location, initTheme, marked } = context;

Copilot uses AI. Check for mistakes.
UpdateButton.className = "btn btn-secondary";
UpdateButton.setAttribute("data-bs-dismiss", "modal");
UpdateButton.innerText = "关闭";
let Version = Object.keys(Response.UpdateHistory)[Object.keys(Response.UpdateHistory).length - 1]
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (98% of all statements in the enclosing function have an explicit semicolon).

Suggested change
let Version = Object.keys(Response.UpdateHistory)[Object.keys(Response.UpdateHistory).length - 1]
let Version = Object.keys(Response.UpdateHistory)[Object.keys(Response.UpdateHistory).length - 1];

Copilot uses AI. Check for mistakes.
} else if (location.pathname == "/contest.php") {
if (UtilityEnabled("AutoCountdown")) {
clock = () => {
}
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (99% of all statements in the enclosing function have an explicit semicolon).

Suggested change
}
};

Copilot uses AI. Check for mistakes.
}
}
let HTMLData = document.querySelector("body > div > div.mt-3 > center > div").innerHTML;
HTMLData = HTMLData.replaceAll("&nbsp;&nbsp;\n&nbsp;&nbsp;", "&nbsp;")
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (99% of all statements in the enclosing function have an explicit semicolon).

Suggested change
HTMLData = HTMLData.replaceAll("&nbsp;&nbsp;\n&nbsp;&nbsp;", "&nbsp;")
HTMLData = HTMLData.replaceAll("&nbsp;&nbsp;\n&nbsp;&nbsp;", "&nbsp;");

Copilot uses AI. Check for mistakes.
HTMLData = HTMLData.replaceAll("&nbsp;&nbsp;\n&nbsp;&nbsp;", "&nbsp;")
HTMLData = HTMLData.replaceAll("<br>开始于: ", "开始时间:")
HTMLData = HTMLData.replaceAll("\n结束于: ", "<br>结束时间:")
HTMLData = HTMLData.replaceAll("\n订正截止日期: ", "<br>订正截止日期:")
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (99% of all statements in the enclosing function have an explicit semicolon).

Suggested change
HTMLData = HTMLData.replaceAll("\n订正截止日期: ", "<br>订正截止日期:")
HTMLData = HTMLData.replaceAll("\n订正截止日期: ", "<br>订正截止日期:");

Copilot uses AI. Check for mistakes.
HTMLData = HTMLData.replaceAll("<br>开始于: ", "开始时间:")
HTMLData = HTMLData.replaceAll("\n结束于: ", "<br>结束时间:")
HTMLData = HTMLData.replaceAll("\n订正截止日期: ", "<br>订正截止日期:")
HTMLData = HTMLData.replaceAll("\n现在时间: ", "当前时间:")
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (99% of all statements in the enclosing function have an explicit semicolon).

Suggested change
HTMLData = HTMLData.replaceAll("\n现在时间: ", "当前时间:")
HTMLData = HTMLData.replaceAll("\n现在时间: ", "当前时间:");

Copilot uses AI. Check for mistakes.
HTMLData = HTMLData.replaceAll("\n结束于: ", "<br>结束时间:")
HTMLData = HTMLData.replaceAll("\n订正截止日期: ", "<br>订正截止日期:")
HTMLData = HTMLData.replaceAll("\n现在时间: ", "当前时间:")
HTMLData = HTMLData.replaceAll("\n状态:", "<br>状态:")
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (99% of all statements in the enclosing function have an explicit semicolon).

Suggested change
HTMLData = HTMLData.replaceAll("\n状态:", "<br>状态:")
HTMLData = HTMLData.replaceAll("\n状态:", "<br>状态:");

Copilot uses AI. Check for mistakes.
let PID = 0;
let IOFilename = "";
if (SearchParams.get("cid") != null && SearchParams.get("pid") != null) {
PID = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-Problem-" + SearchParams.get("pid") + "-PID")
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (98% of all statements in the enclosing function have an explicit semicolon).

Suggested change
PID = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-Problem-" + SearchParams.get("pid") + "-PID")
PID = localStorage.getItem("UserScript-Contest-" + SearchParams.get("cid") + "-Problem-" + SearchParams.get("pid") + "-PID");

Copilot uses AI. Check for mistakes.
- **CodeMirror** - Code editor (for submit page)
- **MathJax** - Math rendering
- **DOMPurify** - HTML sanitization
- **CryptoJS** - MD5 hashing (for passwords)
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

The documentation indicates that CryptoJS is used with MD5 specifically for password hashing, which is a weak and outdated algorithm for protecting credentials. If an attacker obtains these MD5 hashes (for example via database compromise, logs, or intercepted traffic where hashes are reused as passwords), they can crack them quickly using commodity hardware and rainbow tables. Replace MD5-based password hashing with a modern, slow, salted password hashing scheme (e.g., bcrypt, scrypt, Argon2, or at minimum a strong SHA-2/SHA-3-based KDF) and align the client/server flow so that passwords are never protected solely by MD5.

Suggested change
- **CryptoJS** - MD5 hashing (for passwords)
- **CryptoJS** - Cryptographic utilities (do **not** use MD5 for password hashing; use a modern, slow, salted password hashing scheme such as bcrypt, scrypt, or Argon2 instead)

Copilot uses AI. Check for mistakes.
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

Copilot reviewed 51 out of 53 changed files in this pull request and generated no new comments.


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

Copy link
Member

@PythonSmall-Q PythonSmall-Q left a comment

Choose a reason for hiding this comment

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

LGTM

@hendragon-bot hendragon-bot bot added the stale Hurry up! label Jan 10, 2026
@langningchen
Copy link
Member

Are there any current issues with this PR that might be blocking it from being merged?

@boomzero
Copy link
Member Author

Basically, bugs

@hendragon-bot hendragon-bot bot removed the stale Hurry up! label Jan 12, 2026
@hendragon-bot hendragon-bot bot added the stale Hurry up! label Jan 26, 2026
@hendragon-bot hendragon-bot bot closed this Feb 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frozen We are not going to fix this soon size/XXL stale Hurry up! user-script This issue or pull request is related to the main user script

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants