Codeforces 一键隐藏侧边栏脚本
"Codeforces Sidebar Toggle" 是一个用户脚本(UserScript)的名称,它的功能是切换 Codeforces 编程竞赛网站题目页面的侧边栏显示状态。以下是具体解析:
现新增了功能,可以一键复制Markdown形式的链接,主要方便写题解或者小结时使用,其它功能不变。
最近那个网站的号登不上去了,所以最新版本需要手动复制代码到篡改猴中。
代码全部由AI生成
🛠️ 核心功能:
功能 | 作用 |
---|---|
隐藏侧边栏 | 移除干扰元素,让题目区域更宽敞 |
精简顶部按钮 | 只保留必要按钮(如提交按钮) |
内容放大15% | 提升代码和题目文本的可读性 |
自动记忆设置 | 记住你的偏好(下次访问自动应用) |
快捷键切换 (Alt+Q ) |
快速临时切换,不影响自动隐藏设置 |
效果演示
未开启
开启后
添加
首先需要有篡改猴和cf-better
添加新脚本
https://openuserjs.org/scripts/buba_buba/Codeforces_Sidebar_Toggle
代码
// ==UserScript==
// @name ewe→QwQ
// @namespace http://codeforces.com/
// @version 3.0
// @description 在 Codeforces 题目页隐藏侧边栏并提供复制 Markdown 按钮
// @match https://codeforces.com/problemset/problem/*/*
// @match https://codeforces.com/contest/*/problem/*
// @match https://codeforces.com/gym/*/problem/*
// @match https://codeforces.com/group/*/contest/*/problem/*
// @grant GM_setClipboard
// @run-at document-idle
// @license MIT
// ==/UserScript==
(() => {
'use strict';
/*** -------------------- 常量与工具 -------------------- ***/
const STORAGE_KEY = 'cf_auto_hide_sidebar';
const ICON_URL = 'https://raw.githubusercontent.com/hejiehejiehejiehejie/icon/main/lianjie.png';
const BTN_SIZE = 18;
// 预加载图标,减少首次渲染延迟
new Image().src = ICON_URL;
const $ = (sel, root = document) => root.querySelector(sel);
// 判断是否在可编辑输入中(避免快捷键/点击误触)
const inEditable = (e) => {
const t = e.target;
return t && (
t.isContentEditable ||
['INPUT', 'TEXTAREA', 'SELECT'].includes(t.nodeName)
);
};
// 解析 CF 题目 URL,以生成稳定的 Markdown
function parseCFUrl(u) {
// 支持 contest/problemset/group/gym 四类
// 统一提取 (id, index)
const m =
u.match(/^https?:\/\/codeforces\.com\/contest\/(\d+)\/problem\/([A-Z]\d*|[A-Z])\/?$/) ||
u.match(/^https?:\/\/codeforces\.com\/problemset\/problem\/(\d+)\/([A-Z]\d*|[A-Z])\/?$/) ||
u.match(/^https?:\/\/codeforces\.com\/group\/[^/]+\/contest\/(\d+)\/problem\/([A-Z]\d*|[A-Z])\/?$/) ||
u.match(/^https?:\/\/codeforces\.com\/gym\/(\d+)\/problem\/([A-Z]\d*|[A-Z])\/?$/);
return m ? { id: m[1], index: m[2] } : null;
}
/*** -------------------- 样式(用类控制) -------------------- ***/
const STYLE = `
:root {
--qwq-zoom: 1.15;
--qwq-btn-size: ${BTN_SIZE}px;
--qwq-gap: 10px;
}
/* 开关类:整体布局 */
body.cf-hide-sidebar {
overflow-x: hidden !important;
}
body.cf-hide-sidebar #pageContent {
width: 100% !important;
margin-left: 0 !important;
}
body.cf-hide-sidebar.zoomed {
transform-origin: top left;
transform: scale(var(--qwq-zoom));
width: calc(100vw / var(--qwq-zoom));
}
/* 隐藏侧栏 */
body.cf-hide-sidebar #sidebar { display: none !important; }
/* 隐藏右上角多余按钮:仅保留第一个 */
body.cf-hide-sidebar .topRightDiv > *:not(:first-child) {
display: none !important;
}
/* 兜底按钮样式(若无法复用 CF 样式时) */
.cf-md-btn {
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: middle;
height: 26px;
line-height: 26px;
padding: 0 8px;
margin-left: 6px;
border: 1px solid rgba(0,0,0,0.1);
border-radius: 4px;
background: #f7f7f7;
box-sizing: border-box;
cursor: pointer;
user-select: none;
}
/* 我们的两个小控件与工具栏的对齐 */
#cfAutoHideSwitch, #cfMarkdownCopyBtn {
display: inline-flex;
align-items: center;
margin-left: var(--qwq-gap);
vertical-align: middle;
}
#cfMarkdownCopyBtn img {
width: var(--qwq-btn-size);
height: var(--qwq-btn-size);
display: block;
}
#cfAutoHideSwitch input[type="checkbox"] {
width: var(--qwq-btn-size);
height: var(--qwq-btn-size);
cursor: pointer;
margin: 0;
padding: 0;
}
`;
function ensureStyle() {
if (!$('#qwq-style')) {
const s = document.createElement('style');
s.id = 'qwq-style';
s.textContent = STYLE;
document.head.appendChild(s);
}
}
/*** -------------------- UI 元素 -------------------- ***/
function createAutoHideSwitch() {
const wrap = document.createElement('span');
wrap.id = 'cfAutoHideSwitch';
const cb = document.createElement('input');
cb.type = 'checkbox';
cb.title = '自动隐藏侧边栏(Alt+Q 快速切换)';
cb.checked = localStorage.getItem(STORAGE_KEY) === 'on';
cb.addEventListener('change', () => {
localStorage.setItem(STORAGE_KEY, cb.checked ? 'on' : 'off');
});
wrap.appendChild(cb);
return wrap;
}
function createMarkdownCopyButton() {
const parsed = parseCFUrl(location.href);
if (!parsed) return null;
const md = `[CF${parsed.id}${parsed.index}](${location.href})`;
const wrap = document.createElement('span');
wrap.id = 'cfMarkdownCopyBtn';
wrap.title = '复制 Markdown(Ctrl+M)';
const img = document.createElement('img');
img.src = ICON_URL;
img.alt = '复制MD';
const copy = () => {
try {
if (typeof GM_setClipboard !== 'undefined') {
GM_setClipboard(md);
} else if (navigator.clipboard?.writeText) {
navigator.clipboard.writeText(md);
} else {
// 最后兜底
const ta = document.createElement('textarea');
ta.value = md;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
ta.remove();
}
wrap.title = '✅ 已复制!';
setTimeout(() => (wrap.title = '复制 Markdown(Ctrl+M)'), 1500);
} catch { /* 忽略 */ }
};
wrap.addEventListener('click', (e) => {
if (inEditable(e)) return;
copy();
});
// 快捷键(输入框内不触发)
document.addEventListener('keydown', (e) => {
if (inEditable(e)) return;
if (e.ctrlKey && e.key.toLowerCase() === 'm') {
e.preventDefault();
copy();
}
}, { passive: false });
wrap.appendChild(img);
return wrap;
}
/*** -------------------- 行为控制 -------------------- ***/
const Sidebar = {
enable() {
ensureStyle();
document.body.classList.add('cf-hide-sidebar', 'zoomed');
},
disable() {
document.body.classList.remove('cf-hide-sidebar', 'zoomed');
},
toggle() {
document.body.classList.toggle('cf-hide-sidebar');
document.body.classList.toggle('zoomed');
},
get active() {
return document.body.classList.contains('cf-hide-sidebar');
}
};
function setupHotkeys() {
// Alt+Q 开关(输入框内不触发)
document.addEventListener('keydown', (e) => {
if (inEditable(e)) return;
if (e.altKey && e.key.toLowerCase() === 'q') {
e.preventDefault();
Sidebar.toggle();
}
}, { passive: false });
}
function installIntoToolbar() {
const toolbar = $('#problemToolbar');
if (!toolbar || $('#cfAutoHideSwitch')) return false;
// 安装控件
const sw = createAutoHideSwitch();
toolbar.appendChild(sw);
const mdBtn = createMarkdownCopyButton();
if (mdBtn) toolbar.appendChild(mdBtn);
// 根据持久化状态启用布局
if (localStorage.getItem(STORAGE_KEY) === 'on') {
Sidebar.enable();
}
return true;
}
/*** -------------------- 启动流程 -------------------- ***/
function init() {
ensureStyle();
setupHotkeys();
// 如果工具栏已存在,直接安装;否则观察 DOM 直至出现
if (!installIntoToolbar()) {
const mo = new MutationObserver(() => {
if (installIntoToolbar()) mo.disconnect();
});
mo.observe(document.body, { childList: true, subtree: true });
}
}
init();
})();