您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
OnlineMathContest problemsページの問題セルに、得点、分野、いいねしているかどうか表示します。
- // ==UserScript==
- // @name OMC Problems Editor
- // @namespace none
- // @version 1.0.0
- // @description OnlineMathContest problemsページの問題セルに、得点、分野、いいねしているかどうか表示します。
- // @author yuyu
- // @match https://onlinemathcontest.com/problems
- // @grant none
- // @license MIT
- // ==/UserScript==
- (() => {
- 'use strict';
- // ログインチェック
- let is_login = false;
- let username = '';
- const userNameEl = document.getElementById('nav-username');
- if (userNameEl && userNameEl.dataset.uid) {
- is_login = true;
- username = userNameEl.dataset.uid;
- }
- let allProblems = {};
- let favoritesSet = new Set();
- // API 取得
- const get_api = (t) => {
- const url = `https://onlinemathcontest.com/api/problems/list?type=${t}`;
- return fetch(url)
- .then(res => res.json())
- .then(data => {
- const result = {};
- if (data && data.contests) {
- data.contests.forEach(contest => {
- contest.tasks.forEach(task => {
- result[task.title] = {
- point: task.point,
- field: task.field
- };
- });
- });
- }
- return result;
- });
- };
- // favorites取得
- const fetchFavorites = (user) => {
- const url = `https://onlinemathcontest.com/users/${user}/favorites`;
- return fetch(url)
- .then(res => {
- if (!res.ok) throw new Error('Favorites fetch failed');
- return res.text();
- })
- .then(html => {
- const set = new Set();
- const re = />([A-Z0-9]+\(\w\))</g;
- let match;
- while ((match = re.exec(html)) !== null) {
- set.add(match[1].trim());
- }
- return set;
- });
- };
- const problemPromises = ['B', 'R', 'E', 'S', 'O', 'V'].map(t => get_api(t));
- const promises = [Promise.all(problemPromises).then(results => {
- // 各API呼び出しの結果を統合
- results.forEach(data => {
- allProblems = Object.assign(allProblems, data);
- });
- })];
- if (is_login) {
- promises.push(fetchFavorites(username).then(set => { favoritesSet = set; }));
- }
- // オーバーレイ適用、DOM更新を開始
- Promise.all(promises).then(() => {
- Overlay();
- setupMutation();
- });
- function Overlay() {
- document.querySelectorAll('td').forEach(td => {
- td.querySelectorAll('.omc-overlay').forEach(el => el.remove());
- const cellText = td.textContent.trim();
- const prob = allProblems[cellText];
- if (!prob) return;
- if (window.getComputedStyle(td).position === 'static') {
- td.style.position = 'relative';
- }
- if (prob.point !== undefined) {
- const change = document.createElement('span');
- change.classList.add('omc-overlay');
- change.textContent = prob.point;
- change.style.position = 'absolute';
- change.style.right = '2px';
- change.style.bottom = '2px';
- change.style.fontSize = '10px';
- change.style.color = 'gray';
- change.style.pointerEvents = 'none';
- change.style.zIndex = '0';
- td.appendChild(change);
- }
- if (prob.field !== undefined) {
- const change = document.createElement('span');
- change.classList.add('omc-overlay');
- change.textContent = prob.field;
- change.style.position = 'absolute';
- change.style.left = '2px';
- change.style.bottom = '2px';
- change.style.fontSize = '10px';
- change.style.color = 'gray';
- change.style.pointerEvents = 'none';
- change.style.zIndex = '0';
- td.appendChild(change);
- }
- if (favoritesSet.has(cellText)) {
- const change = document.createElement('span');
- change.classList.add('omc-overlay');
- change.textContent = '❤️'; // かわいいハート。らぶ。
- change.style.position = 'absolute';
- change.style.right = '2px';
- change.style.top = '2px';
- change.style.fontSize = '10px';
- change.style.pointerEvents = 'none';
- change.style.zIndex = '0';
- td.appendChild(change);
- }
- });
- }
- function applyOverlays() {
- Overlay();
- }
- function setupMutation() {
- let Timer = null;
- const delay = 500;
- const CallBack = () => {
- if (Timer) clearTimeout(Timer);
- Timer = setTimeout(() => {
- applyOverlays();
- Timer = null;
- }, delay);
- };
- const observer = new MutationObserver(CallBack);
- observer.observe(document.body, { childList: true, subtree: true });
- window.addEventListener('scroll', applyOverlays);
- window.addEventListener('resize', applyOverlays);
- }
- })();