// ==UserScript==
// @name 移动端优化广告标记器(增强版)
// @namespace http://tampermonkey.net/
// @version 14.3
// @description 专为手机优化的广告标记工具,支持拖拽菜单、长按标记和二级目录菜单,预览时可临时拦截
// @author 优化助手
// @match *://*/*
// @icon https://img.icons8.com/color/96/000000/ad-block.png
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_notification
// @grant GM_deleteValue
// @grant GM_listValues
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 检查是否在Tampermonkey环境中
if (typeof GM_registerMenuCommand === 'undefined') {
console.error('Tampermonkey API不可用,请确保脚本在Tampermonkey中运行');
showBrowserAlert();
return;
}
function showBrowserAlert() {
const alertDiv = document.createElement('div');
alertDiv.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: #ff3b30;
color: white;
padding: 15px 20px;
border-radius: 10px;
z-index: 999999;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
font-family: Arial, sans-serif;
text-align: center;
max-width: 90vw;
`;
alertDiv.innerHTML = `
⚠️ 脚本运行环境错误
请确保在Tampermonkey中运行此脚本
油猴菜单功能需要Tampermonkey扩展
`;
document.body.appendChild(alertDiv);
setTimeout(() => alertDiv.remove(), 5000);
}
// 配置
const CONFIG = {
colors: {
marker: '#ff3b30',
preview: '#34c759',
block: '#ff9500',
background: 'rgba(255, 255, 255, 0.95)',
card: '#f2f2f7',
text: '#1d1d1f',
textSecondary: '#8e8e93',
border: '#c7c7cc',
success: '#34c759',
warning: '#ffcc00',
error: '#ff3b30',
info: '#007aff'
},
sizes: {
menuWidth: '75vw',
menuMinWidth: 220,
menuMaxWidth: 400,
menuHeight: '50vh',
menuMinHeight: 200,
menuMaxHeight: 500,
compactHeight: '35vh',
buttonHeight: 40,
touchSize: 40,
fontSize: 13,
iconSize: 18,
borderRadius: 10
},
behavior: {
autoBlock: true,
swipeToClose: true,
vibration: true,
doubleTapDelay: 300,
longPressDelay: 800,
previewDuration: 2000,
defaultCompactMode: true,
autoHideMenu: true,
hideDelay: 2000,
immediateBlock: true,
draggableMenu: true,
rememberMenuPosition: true,
resizableMenu: true
},
gestures: {
swipeThreshold: 50,
velocityThreshold: 0.3,
dragThreshold: 5,
resizeThreshold: 10
}
};
// 状态管理
const STATE = {
isMarkerMode: false,
isBlockingEnabled: true,
isPreviewMode: false,
isMenuVisible: false,
isCompactMode: CONFIG.behavior.defaultCompactMode,
menuAutoHideTimer: null,
isTemporaryBlocking: false,
temporaryBlockedElements: [],
settings: {
showToast: true,
enableVibration: true,
enableDoubleTap: true,
enableLongPress: true,
autoExpandMenu: false,
highlightColor: '#ff3b30',
darkMode: false,
draggableMenu: true,
resizableMenu: true,
menuPosition: { x: 50, y: 50 },
menuSize: { width: 300, height: 350 },
rememberMenuPosition: true,
showMarkerHint: true,
vibrationStrength: 'medium'
},
adRules: [],
blockedElements: [],
currentDomain: window.location.hostname,
currentSelector: '',
statistics: {
totalBlocked: 0,
todayBlocked: 0,
rulesCount: 0,
domainsCount: 0,
lastUpdate: null
},
elements: {
menu: null,
floatingBtn: null,
controlPanel: null,
settingsPanel: null
},
touchState: {
startX: 0,
startY: 0,
startTime: 0,
isSwiping: false,
isDraggingMenu: false,
isResizingMenu: false,
lastTapTime: 0,
longPressTimer: null,
longPressTarget: null,
longPressActive: false,
dragStartX: 0,
dragStartY: 0,
menuStartX: 0,
menuStartY: 0,
resizeStartX: 0,
resizeStartY: 0,
menuStartWidth: 0,
menuStartHeight: 0
},
menuCommands: [],
expandedDomains: new Set()
};
// ==================== 移动端优化的CSS ====================
GM_addStyle(`
/* 重置和基础样式 */
#marker-mobile-menu, #marker-floating-btn, .marker-indicator {
all: initial;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
box-sizing: border-box;
}
/* 悬浮按钮 - 修复显示逻辑 */
#marker-floating-btn {
position: fixed;
bottom: 80px;
right: 20px;
width: 50px;
height: 50px;
background: ${CONFIG.colors.marker};
color: white;
border: none;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
cursor: pointer;
z-index: 999998;
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
opacity: 0;
transform: scale(0.8);
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
user-select: none;
pointer-events: none;
}
#marker-floating-btn.visible {
opacity: 1;
transform: scale(1);
pointer-events: auto;
}
#marker-floating-btn:active {
transform: scale(0.95);
}
/* 标记模式指示器 */
.marker-indicator {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, ${CONFIG.colors.marker}, #ff6b6b);
color: white;
padding: 10px 20px;
border-radius: 25px;
font-size: 14px;
font-weight: 600;
z-index: 999997;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
opacity: 0;
transition: opacity 0.3s;
white-space: nowrap;
pointer-events: none;
}
.marker-indicator.visible {
opacity: 1;
}
/* 移动端菜单 - 可拖动和调整大小 */
#marker-mobile-menu {
position: fixed;
min-width: ${CONFIG.sizes.menuMinWidth}px;
min-height: ${CONFIG.sizes.menuMinHeight}px;
max-width: 90vw;
max-height: 90vh;
background: ${CONFIG.colors.background};
backdrop-filter: blur(20px);
border-radius: ${CONFIG.sizes.borderRadius}px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
z-index: 999999;
opacity: 0;
visibility: hidden;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transform: scale(0.9);
border: 1px solid rgba(255,255,255,0.1);
user-select: none;
cursor: default;
resize: none;
}
#marker-mobile-menu.visible {
opacity: 1;
visibility: visible;
transform: scale(1);
}
#marker-mobile-menu.compact {
height: ${CONFIG.sizes.compactHeight};
max-height: ${CONFIG.sizes.menuMaxHeight}px;
}
#marker-mobile-menu.expanded {
height: ${CONFIG.sizes.menuHeight};
max-height: ${CONFIG.sizes.menuMaxHeight}px;
}
#marker-mobile-menu.marker-mode-active {
border: 2px solid ${CONFIG.colors.marker};
}
#marker-mobile-menu.draggable .menu-header {
cursor: move;
user-select: none;
}
/* 菜单头部的拖动区域 */
.menu-drag-area {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 40px;
cursor: move;
z-index: 1000;
}
/* 关闭按钮样式增强 */
.menu-close-btn {
width: 30px;
height: 30px;
border: none;
border-radius: 8px;
background: rgba(255, 59, 48, 0.1) !important;
color: ${CONFIG.colors.error} !important;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 16px;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
user-select: none;
position: relative;
z-index: 1001;
}
.menu-close-btn:active {
background: rgba(255, 59, 48, 0.2) !important;
transform: scale(0.9) !important;
}
/* 确保按钮在暗色模式下也可见 */
.dark-mode .menu-close-btn {
background: rgba(255, 59, 48, 0.2) !important;
color: #ff7b7b !important;
}
/* 菜单头部的拖动提示 */
.drag-handle {
display: inline-block;
margin-left: 8px;
font-size: 14px;
opacity: 0.6;
cursor: move;
}
/* 调整大小手柄 */
.resize-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
cursor: nwse-resize;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.1);
border-top-left-radius: 8px;
color: ${CONFIG.colors.textSecondary};
font-size: 12px;
}
.resize-handle:hover {
background: rgba(0, 0, 0, 0.2);
}
/* 暗色模式 */
#marker-mobile-menu.dark-mode {
background: rgba(0, 0, 0, 0.95);
color: #ffffff;
border: 1px solid rgba(255,255,255,0.1);
}
.dark-mode {
color: #ffffff !important;
}
.dark-mode .menu-header {
background: rgba(30, 30, 30, 0.9) !important;
color: #ffffff !important;
}
.dark-mode .card {
background: rgba(40, 40, 40, 0.9) !important;
border: 1px solid rgba(255,255,255,0.1) !important;
color: #ffffff !important;
}
.dark-mode .quick-action-btn {
background: rgba(60, 60, 60, 0.9) !important;
color: #ffffff !important;
}
/* 菜单容器 */
.menu-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
/* 菜单头部 */
.menu-header {
padding: 16px;
background: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid ${CONFIG.colors.border};
flex-shrink: 0;
position: relative;
}
.menu-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 18px;
font-weight: 600;
color: ${CONFIG.colors.text};
}
.menu-controls {
position: absolute;
top: 16px;
right: 16px;
display: flex;
gap: 8px;
z-index: 1002;
}
.icon-btn {
width: 30px;
height: 30px;
border: none;
border-radius: 8px;
background: ${CONFIG.colors.card};
color: ${CONFIG.colors.text};
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 16px;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
user-select: none;
}
.icon-btn:active {
transform: scale(0.95);
background: ${CONFIG.colors.border};
}
/* 菜单内容 */
.menu-content {
flex: 1;
overflow-y: auto;
padding: 16px;
padding-bottom: 60px;
}
/* 快速操作区域 */
.quick-actions {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
margin-bottom: 16px;
}
.quick-action-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 60px;
border: none;
border-radius: ${CONFIG.sizes.borderRadius}px;
background: ${CONFIG.colors.card};
color: ${CONFIG.colors.text};
font-size: 12px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
padding: 8px 4px;
user-select: none;
}
.quick-action-btn:active {
transform: scale(0.95);
background: ${CONFIG.colors.border};
}
.quick-action-btn span:first-child {
font-size: 20px;
margin-bottom: 4px;
}
/* 卡片 */
.card {
background: ${CONFIG.colors.card};
border-radius: ${CONFIG.sizes.borderRadius}px;
padding: 16px;
margin-bottom: 16px;
border: 1px solid ${CONFIG.colors.border};
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.card-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
color: ${CONFIG.colors.text};
}
/* 元素信息 - 修复样式 */
.element-info {
font-size: 12px;
}
.element-line {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
}
.element-label {
color: ${CONFIG.colors.textSecondary};
min-width: 50px;
flex-shrink: 0;
}
.element-value {
color: ${CONFIG.colors.text};
font-weight: 500;
text-align: right;
flex: 1;
word-break: break-all;
padding-left: 10px;
}
.selector-display {
margin-top: 10px;
padding: 10px;
background: rgba(0,0,0,0.05);
border-radius: 8px;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 11px;
word-break: break-all;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
max-height: 100px;
overflow-y: auto;
}
.selector-display:active {
background: rgba(0,0,0,0.1);
}
/* 按钮网格 */
.button-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin-bottom: 12px;
}
.primary-btn {
height: ${CONFIG.sizes.buttonHeight}px;
border: none;
border-radius: ${CONFIG.sizes.borderRadius}px;
background: ${CONFIG.colors.info};
color: white;
font-size: 13px;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
user-select: none;
}
.primary-btn:active {
transform: scale(0.98);
opacity: 0.9;
}
.primary-btn.success {
background: ${CONFIG.colors.success};
}
.primary-btn.warning {
background: ${CONFIG.colors.warning};
}
.primary-btn.danger {
background: ${CONFIG.colors.error};
}
/* 规则列表 */
.rules-list {
max-height: 200px;
overflow-y: auto;
}
.rule-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background: white;
border-radius: 8px;
margin-bottom: 8px;
border: 1px solid ${CONFIG.colors.border};
}
.rule-selector {
font-size: 11px;
color: ${CONFIG.colors.text};
word-break: break-all;
flex: 1;
}
.action-btn {
width: 28px;
height: 28px;
border: none;
border-radius: 6px;
background: transparent;
color: ${CONFIG.colors.textSecondary};
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
-webkit-tap-highlight-color: transparent;
}
.action-btn.delete:hover {
color: ${CONFIG.colors.error};
}
/* 菜单底部 */
.menu-footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 12px 16px;
background: rgba(255, 255, 255, 0.9);
border-top: 1px solid ${CONFIG.colors.border};
display: flex;
justify-content: space-between;
align-items: center;
}
.status-indicators {
display: flex;
gap: 12px;
}
.status-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: ${CONFIG.colors.textSecondary};
cursor: pointer;
-webkit-tap-highlight-color: transparent;
padding: 4px 6px;
border-radius: 6px;
transition: background 0.2s;
}
.status-item:active {
background: rgba(0,0,0,0.05);
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.status-dot.active {
background: ${CONFIG.colors.success};
}
.status-dot.inactive {
background: ${CONFIG.colors.border};
}
/* 大小切换按钮 */
.size-toggle {
position: absolute;
bottom: -12px;
left: 50%;
transform: translateX(-50%);
width: 40px;
height: 24px;
background: ${CONFIG.colors.card};
border: 1px solid ${CONFIG.colors.border};
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 12px;
z-index: 1;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
}
.size-toggle:active {
background: ${CONFIG.colors.border};
}
/* 控制面板样式 */
.control-panel {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90vw;
max-width: 400px;
max-height: 80vh;
background: ${CONFIG.colors.background};
backdrop-filter: blur(20px);
border-radius: ${CONFIG.sizes.borderRadius}px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
z-index: 1000000;
display: flex;
flex-direction: column;
overflow: hidden;
border: 1px solid rgba(255,255,255,0.1);
}
.control-header {
padding: 16px;
background: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid ${CONFIG.colors.border};
display: flex;
justify-content: space-between;
align-items: center;
}
.control-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 18px;
font-weight: 600;
color: ${CONFIG.colors.text};
}
.control-content {
flex: 1;
overflow-y: auto;
padding: 16px;
}
/* 控制面板的三个部分 */
.control-section {
margin-bottom: 20px;
}
.section-header {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: 600;
color: ${CONFIG.colors.text};
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid ${CONFIG.colors.border};
}
.stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin-bottom: 16px;
}
.stat-item {
background: ${CONFIG.colors.card};
border-radius: ${CONFIG.sizes.borderRadius}px;
padding: 12px;
text-align: center;
border: 1px solid ${CONFIG.colors.border};
}
.stat-value {
font-size: 20px;
font-weight: 700;
color: ${CONFIG.colors.info};
margin-bottom: 4px;
}
.stat-label {
font-size: 12px;
color: ${CONFIG.colors.textSecondary};
}
.tools-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.tool-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 70px;
border: none;
border-radius: ${CONFIG.sizes.borderRadius}px;
background: ${CONFIG.colors.card};
color: ${CONFIG.colors.text};
font-size: 12px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
padding: 8px 4px;
}
.tool-btn:active {
transform: scale(0.95);
background: ${CONFIG.colors.border};
}
.tool-btn span:first-child {
font-size: 20px;
margin-bottom: 4px;
}
/* 规则管理区域 */
.rules-management {
max-height: 200px;
overflow-y: auto;
border: 1px solid ${CONFIG.colors.border};
border-radius: ${CONFIG.sizes.borderRadius}px;
padding: 10px;
background: ${CONFIG.colors.card};
}
.rule-manage-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.rule-manage-item:last-child {
border-bottom: none;
}
.rule-info {
flex: 1;
}
.rule-domain {
font-size: 11px;
color: ${CONFIG.colors.textSecondary};
margin-bottom: 2px;
}
.rule-selector-short {
font-size: 10px;
color: ${CONFIG.colors.text};
word-break: break-all;
}
/* 拦截目录样式 */
.directory-section {
max-height: 200px;
overflow-y: auto;
border: 1px solid ${CONFIG.colors.border};
border-radius: ${CONFIG.sizes.borderRadius}px;
padding: 10px;
background: ${CONFIG.colors.card};
margin-top: 10px;
}
.directory-item {
padding: 8px;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.directory-item:last-child {
border-bottom: none;
}
.domain-header {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
padding: 4px 0;
}
.domain-info {
flex: 1;
}
.domain-name {
font-size: 12px;
font-weight: 500;
color: ${CONFIG.colors.text};
margin-bottom: 2px;
}
.rule-count {
font-size: 10px;
color: ${CONFIG.colors.textSecondary};
}
.expand-toggle {
width: 24px;
height: 24px;
border: none;
background: transparent;
color: ${CONFIG.colors.textSecondary};
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
transition: transform 0.2s;
border-radius: 4px;
}
.expand-toggle:hover {
background: rgba(0,0,0,0.05);
}
.domain-expanded .expand-toggle {
transform: rotate(180deg);
}
.domain-rules {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.domain-expanded .domain-rules {
max-height: 300px;
overflow-y: auto;
margin-top: 8px;
padding: 8px;
background: rgba(0,0,0,0.03);
border-radius: 8px;
border: 1px solid rgba(0,0,0,0.05);
}
.domain-rule-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 8px;
border-bottom: 1px solid rgba(0,0,0,0.05);
background: rgba(255,255,255,0.8);
border-radius: 6px;
margin-bottom: 4px;
}
.domain-rule-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
.domain-rule-info {
flex: 1;
margin-right: 8px;
}
.domain-rule-selector {
font-size: 9px;
color: ${CONFIG.colors.text};
word-break: break-all;
line-height: 1.3;
}
.domain-rule-match {
font-size: 8px;
color: ${CONFIG.colors.textSecondary};
margin-top: 2px;
}
.domain-rule-actions {
display: flex;
gap: 4px;
}
.domain-rule-delete {
width: 22px;
height: 22px;
border: none;
border-radius: 4px;
background: rgba(255, 59, 48, 0.1);
color: ${CONFIG.colors.error};
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 12px;
-webkit-tap-highlight-color: transparent;
}
.domain-rule-delete:hover {
background: rgba(255, 59, 48, 0.2);
}
/* 设置面板 */
.settings-panel {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90vw;
max-width: 400px;
max-height: 80vh;
background: ${CONFIG.colors.background};
backdrop-filter: blur(20px);
border-radius: ${CONFIG.sizes.borderRadius}px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
z-index: 1000000;
display: flex;
flex-direction: column;
overflow: hidden;
border: 1px solid rgba(255,255,255,0.1);
}
.settings-header {
padding: 16px;
background: rgba(255, 255, 255, 0.9);
border-bottom: 1px solid ${CONFIG.colors.border};
}
.settings-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 18px;
font-weight: 600;
color: ${CONFIG.colors.text};
}
.settings-content {
flex: 1;
overflow-y: auto;
padding: 16px;
}
.settings-section {
margin-bottom: 20px;
}
.section-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
font-weight: 600;
color: ${CONFIG.colors.text};
margin-bottom: 12px;
}
.setting-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.setting-info {
flex: 1;
}
.setting-label {
font-size: 13px;
font-weight: 500;
color: ${CONFIG.colors.text};
margin-bottom: 2px;
}
.setting-description {
font-size: 11px;
color: ${CONFIG.colors.textSecondary};
}
/* 开关样式 */
.switch {
position: relative;
display: inline-block;
width: 44px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: ${CONFIG.colors.border};
transition: .3s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: ${CONFIG.colors.info};
}
input:checked + .slider:before {
transform: translateX(20px);
}
/* 设置按钮 */
.settings-footer {
padding: 16px;
background: rgba(255, 255, 255, 0.9);
border-top: 1px solid ${CONFIG.colors.border};
display: flex;
gap: 12px;
}
.settings-btn {
flex: 1;
height: 40px;
border: none;
border-radius: ${CONFIG.sizes.borderRadius}px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
-webkit-tap-highlight-color: transparent;
transition: all 0.2s;
}
.settings-btn.primary {
background: ${CONFIG.colors.info};
color: white;
}
.settings-btn.secondary {
background: ${CONFIG.colors.card};
color: ${CONFIG.colors.text};
border: 1px solid ${CONFIG.colors.border};
}
.settings-btn:active {
transform: scale(0.98);
opacity: 0.9;
}
/* Toast提示 */
#marker-toast {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: ${CONFIG.colors.text};
color: white;
padding: 12px 20px;
border-radius: ${CONFIG.sizes.borderRadius}px;
font-size: 13px;
font-weight: 500;
z-index: 1000001;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
opacity: 0;
transition: opacity 0.3s;
white-space: nowrap;
pointer-events: none;
}
/* 元素高亮 */
.marker-highlight {
outline: 3px solid ${CONFIG.colors.marker} !important;
outline-offset: 2px !important;
position: relative !important;
z-index: 999990 !important;
background-color: rgba(255, 59, 48, 0.1) !important;
}
.preview-highlight {
outline: 3px dashed ${CONFIG.colors.preview} !important;
outline-offset: 3px !important;
position: relative !important;
z-index: 999990 !important;
background-color: rgba(52, 199, 89, 0.15) !important;
box-shadow: 0 0 10px rgba(52, 199, 89, 0.3) !important;
animation: preview-pulse 1s ease-in-out infinite alternate;
}
@keyframes preview-pulse {
from {
outline-width: 2px;
box-shadow: 0 0 5px rgba(52, 199, 89, 0.3);
}
to {
outline-width: 4px;
box-shadow: 0 0 15px rgba(52, 199, 89, 0.6);
}
}
/* 临时拦截样式 */
.temporary-blocked {
opacity: 0.5 !important;
filter: grayscale(80%) !important;
display: block !important;
}
.element-blocked {
display: none !important;
}
/* 当拦截功能关闭时的样式 */
.interception-disabled .permanent-blocked {
display: block !important;
opacity: 0.5 !important;
filter: blur(1px) !important;
transition: all 0.3s ease;
}
.interception-disabled .permanent-blocked:hover {
opacity: 1 !important;
filter: none !important;
}
/* 确保拦截状态正确显示 */
body.interception-disabled {
position: relative;
}
body.interception-disabled::after {
content: '拦截功能已暂停';
position: fixed;
top: 10px;
right: 10px;
background: rgba(255, 59, 48, 0.9);
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
z-index: 999999;
pointer-events: none;
animation: fadeInOut 3s ease-in-out;
}
@keyframes fadeInOut {
0%, 100% { opacity: 0; }
10%, 90% { opacity: 1; }
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 30px 20px;
color: ${CONFIG.colors.textSecondary};
}
.empty-icon {
font-size: 32px;
margin-bottom: 10px;
opacity: 0.5;
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(0,0,0,0.2);
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0,0,0,0.3);
}
/* 长按标记指示器 */
.long-press-indicator {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: ${CONFIG.colors.marker};
color: white;
padding: 8px 16px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
z-index: 999999;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
.long-press-indicator.visible {
opacity: 1;
}
/* 防止系统长按菜单 */
body.marker-mode-active * {
-webkit-touch-callout: none !important;
-webkit-user-select: none !important;
user-select: none !important;
}
/* 仅在标记模式时添加 */
body.marker-mode-active {
-webkit-touch-callout: none !important;
-webkit-user-select: none !important;
user-select: none !important;
}
/* 长按标记指示器 - 新增样式 */
.long-press-hint {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px 20px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
z-index: 999999;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
white-space: nowrap;
}
.long-press-hint.visible {
opacity: 1;
}
/* 移除阻止页面滚动的样式 */
body.marker-mode-active {
overflow: auto !important;
-webkit-overflow-scrolling: touch !important;
}
/* 允许标记模式下页面滚动 */
body.marker-mode-active * {
-webkit-touch-callout: default !important;
-webkit-user-select: auto !important;
user-select: auto !important;
pointer-events: auto !important;
}
/* 迷你统计样式 */
.stats-mini {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
.stat-item-mini {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 8px;
background: rgba(0,0,0,0.03);
border-radius: 6px;
font-size: 11px;
}
.stat-label-mini {
color: ${CONFIG.colors.textSecondary};
}
.stat-value-mini {
font-weight: 600;
color: ${CONFIG.colors.info};
}
.domain-rules-list {
max-height: 150px;
overflow-y: auto;
}
.domain-rule-item-mini {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 8px;
margin-bottom: 4px;
background: rgba(0,0,0,0.03);
border-radius: 6px;
font-size: 10px;
border: 1px solid rgba(0,0,0,0.05);
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.domain-rule-item-mini:active {
background: rgba(0,0,0,0.08);
}
.domain-rule-selector-mini {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 8px;
color: ${CONFIG.colors.text};
}
.domain-rule-actions-mini {
display: flex;
gap: 4px;
}
.domain-rule-delete-mini {
width: 20px;
height: 20px;
border: none;
border-radius: 4px;
background: rgba(255, 59, 48, 0.1);
color: ${CONFIG.colors.error};
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 10px;
-webkit-tap-highlight-color: transparent;
}
.domain-rule-delete-mini:hover {
background: rgba(255, 59, 48, 0.2);
}
.dark-mode .status-item:active {
background: rgba(255,255,255,0.05);
}
/* 高级操作帮助 */
.advanced-help {
font-size: 11px;
color: ${CONFIG.colors.textSecondary};
padding: 8px;
margin-bottom: 10px;
background: rgba(0,0,0,0.05);
border-radius: 6px;
}
.dark-mode .advanced-help {
background: rgba(255,255,255,0.05);
}
/* 规则项状态 */
.rule-status {
font-size: 9px;
padding: 2px 4px;
border-radius: 4px;
margin-left: 4px;
}
.rule-status.valid {
background: rgba(52, 199, 89, 0.1);
color: ${CONFIG.colors.success};
}
.rule-status.invalid {
background: rgba(255, 59, 48, 0.1);
color: ${CONFIG.colors.error};
}
/* 预览时临时拦截样式 */
.preview-highlight.temporary-blocked {
outline: 3px dashed ${CONFIG.colors.preview} !important;
outline-offset: 3px !important;
position: relative !important;
z-index: 999990 !important;
background-color: rgba(52, 199, 89, 0.15) !important;
box-shadow: 0 0 10px rgba(52, 199, 89, 0.3) !important;
animation: preview-pulse 1s ease-in-out infinite alternate;
}
`);
// ==================== 核心功能 ====================
// 触觉反馈 - 支持强度调节
function vibrate(type = 'light') {
if (STATE.settings.vibrationStrength === 'off' || !window.navigator.vibrate) return;
const strengthMap = {
'light': 0.5,
'medium': 1,
'strong': 1.5
};
const strength = strengthMap[STATE.settings.vibrationStrength] || 1;
const patterns = {
light: [30 * strength],
medium: [50 * strength],
heavy: [100 * strength],
success: [30 * strength, 50, 30 * strength],
error: [50 * strength, 100, 50 * strength]
};
window.navigator.vibrate(patterns[type] || [30 * strength]);
}
// 生成元素选择器
function generateSelector(element) {
if (!element || !element.tagName) return '';
if (element.id && element.id.trim()) {
const idSelector = `#${CSS.escape(element.id)}`;
try {
const matches = document.querySelectorAll(idSelector);
if (matches.length === 1) {
return idSelector;
}
} catch (e) {}
}
const path = [];
let current = element;
while (current && current !== document.body) {
let selector = current.tagName.toLowerCase();
if (current.id && current.id.trim()) {
selector += `#${CSS.escape(current.id)}`;
path.unshift(selector);
break;
}
if (current.className && typeof current.className === 'string') {
const classes = current.className.trim().split(/\s+/)
.filter(c => c.length > 0 && c.length < 30)
.filter(c => !c.includes(':') && !c.includes('hover') && !c.includes('active'));
if (classes.length > 0) {
const classPart = classes.map(c => `.${CSS.escape(c)}`).join('');
selector += classPart;
}
}
const attrs = ['name', 'type', 'alt', 'title', 'href', 'src', 'data-id', 'data-ad', 'data-role', 'data-testid'];
for (const attr of attrs) {
const value = current.getAttribute(attr);
if (value && value.trim() && value.length < 50) {
selector += `[${attr}="${CSS.escape(value.trim())}"]`;
break;
}
}
let siblingIndex = 1;
let sibling = current.previousElementSibling;
while (sibling) {
if (sibling.tagName === current.tagName) {
siblingIndex++;
}
sibling = sibling.previousElementSibling;
}
if (siblingIndex > 1) {
selector += `:nth-of-type(${siblingIndex})`;
}
path.unshift(selector);
current = current.parentElement;
}
const fullSelector = path.join(' > ');
try {
const matches = document.querySelectorAll(fullSelector);
if (matches.length > 0) {
for (let i = 1; i < Math.min(3, path.length); i++) {
const testSelector = path.slice(-i).join(' > ');
const testMatches = document.querySelectorAll(testSelector);
if (testMatches.length === 1) {
return testSelector;
}
}
return fullSelector;
}
} catch (e) {
console.error('选择器生成错误:', e);
}
let fallbackSelector = element.tagName.toLowerCase();
if (element.className && typeof element.className === 'string') {
const classes = element.className.trim().split(/\s+/).filter(c => c.length > 0);
if (classes.length > 0) {
fallbackSelector += `.${CSS.escape(classes[0])}`;
}
}
return fallbackSelector;
}
// 测试选择器是否有效
function testSelector(selector) {
if (!selector || selector.trim() === '') {
return {
valid: false,
error: '选择器为空',
count: 0,
elements: []
};
}
try {
const elements = document.querySelectorAll(selector);
const elementArray = Array.from(elements);
const visibleElements = elementArray.filter(el => {
try {
const style = window.getComputedStyle(el);
return style.display !== 'none' &&
style.visibility !== 'hidden' &&
style.opacity !== '0';
} catch (e) {
return true;
}
});
return {
valid: true,
count: visibleElements.length,
elements: visibleElements,
allElements: elementArray
};
} catch (e) {
console.error('选择器测试失败:', e);
return {
valid: false,
error: e.message,
count: 0,
elements: []
};
}
}
// 加载广告规则
function loadAdRules() {
try {
const saved = GM_getValue('adBlockRules', '[]');
STATE.adRules = JSON.parse(saved);
console.log(`加载了 ${STATE.adRules.length} 条规则`);
updateStatistics();
} catch (e) {
console.error('加载规则失败:', e);
STATE.adRules = [];
}
}
// 保存广告规则
function saveAdRules() {
try {
GM_setValue('adBlockRules', JSON.stringify(STATE.adRules));
console.log('规则已保存');
updateStatistics();
} catch (e) {
console.error('保存规则失败:', e);
}
}
// 加载设置
function loadSettings() {
try {
const saved = GM_getValue('adMarkerSettings', '{}');
const settings = JSON.parse(saved);
STATE.settings = {
...STATE.settings,
...settings
};
console.log('设置已加载:', STATE.settings);
} catch (e) {
console.error('加载设置失败:', e);
}
}
// 保存设置
function saveSettings() {
try {
GM_setValue('adMarkerSettings', JSON.stringify(STATE.settings));
console.log('设置已保存:', STATE.settings);
if (STATE.elements.menu) {
if (STATE.settings.darkMode) {
STATE.elements.menu.classList.add('dark-mode');
} else {
STATE.elements.menu.classList.remove('dark-mode');
}
}
if (STATE.settings.highlightColor && STATE.settings.highlightColor !== CONFIG.colors.marker) {
updateHighlightColor(STATE.settings.highlightColor);
}
return true;
} catch (e) {
console.error('保存设置失败:', e);
return false;
}
}
// 更新高亮颜色
function updateHighlightColor(color) {
const styleId = 'marker-highlight-color';
let style = document.getElementById(styleId);
if (!style) {
style = document.createElement('style');
style.id = styleId;
document.head.appendChild(style);
}
style.textContent = `
.marker-highlight {
outline-color: ${color} !important;
background-color: ${color}20 !important;
}
.marker-indicator {
background: linear-gradient(135deg, ${color}, ${color}cc) !important;
}
#marker-floating-btn {
background: ${color} !important;
}
.primary-btn {
background: ${color} !important;
}
`;
}
// 更新统计数据
function updateStatistics() {
const now = new Date();
const today = now.toDateString();
STATE.statistics.rulesCount = STATE.adRules.length;
const domains = new Set();
STATE.adRules.forEach(rule => {
domains.add(rule.domain || '全局');
});
STATE.statistics.domainsCount = domains.size;
const currentDomainRules = STATE.adRules.filter(rule =>
!rule.domain || rule.domain === STATE.currentDomain
).length;
const blockedCount = document.querySelectorAll('.element-blocked.permanent-blocked').length;
try {
const stats = GM_getValue('adMarkerStatistics', '{}');
const savedStats = JSON.parse(stats);
STATE.statistics.totalBlocked = savedStats.totalBlocked || 0;
STATE.statistics.todayBlocked = savedStats.todayBlocked || 0;
STATE.statistics.lastUpdate = savedStats.lastUpdate || null;
if (STATE.statistics.lastUpdate !== today) {
STATE.statistics.todayBlocked = 0;
}
STATE.statistics.totalBlocked += blockedCount;
STATE.statistics.todayBlocked += blockedCount;
} catch (e) {
STATE.statistics.totalBlocked = blockedCount;
STATE.statistics.todayBlocked = blockedCount;
}
STATE.statistics.lastUpdate = today;
GM_setValue('adMarkerStatistics', JSON.stringify(STATE.statistics));
return {
totalBlocked: STATE.statistics.totalBlocked,
todayBlocked: STATE.statistics.todayBlocked,
rulesCount: STATE.statistics.rulesCount,
currentDomainRules: currentDomainRules,
domainsCount: STATE.statistics.domainsCount,
blockedCount: blockedCount
};
}
// 拦截元素
function blockElements() {
if (!STATE.isBlockingEnabled && !STATE.isTemporaryBlocking) {
console.log('拦截功能已禁用,跳过永久拦截');
return 0;
}
STATE.blockedElements = [];
const domainRules = STATE.adRules.filter(rule =>
!rule.domain || rule.domain === STATE.currentDomain
);
if (domainRules.length === 0) {
console.log('当前域名没有永久规则');
return 0;
}
let blockedCount = 0;
domainRules.forEach((rule, index) => {
try {
const elements = document.querySelectorAll(rule.selector);
elements.forEach((element, elementIndex) => {
// 只有在拦截功能开启时才应用永久拦截
if (STATE.isBlockingEnabled) {
if (!element.classList.contains('permanent-blocked')) {
element.classList.add('element-blocked');
element.classList.add('permanent-blocked');
blockedCount++;
STATE.blockedElements.push({
element: element,
ruleIndex: index,
selector: rule.selector
});
}
} else if (element.classList.contains('permanent-blocked')) {
// 如果拦截功能关闭,移除永久拦截
element.classList.remove('permanent-blocked');
element.classList.remove('element-blocked');
}
});
} catch (e) {
console.error(`应用规则 ${rule.selector} 时出错:`, e);
}
});
updateBlockedCount();
updateStatistics();
console.log(`本次拦截完成,共拦截了 ${blockedCount} 个元素`);
setTimeout(() => {
updateMiniStats();
}, 100);
return blockedCount;
}
// 移除拦截
function unblockElements() {
const blockedElements = document.querySelectorAll('.element-blocked');
blockedElements.forEach(element => {
// 只移除永久拦截的
if (element.classList.contains('permanent-blocked')) {
element.classList.remove('permanent-blocked');
element.classList.remove('element-blocked');
}
});
STATE.blockedElements = [];
updateBlockedCount();
console.log(`已移除永久拦截,临时拦截仍然有效`);
return blockedElements.length;
}
// 强制重新拦截所有规则
function forceReBlock() {
document.querySelectorAll('.element-blocked.permanent-blocked').forEach(element => {
element.classList.remove('permanent-blocked');
element.classList.remove('element-blocked');
});
STATE.blockedElements = [];
const blockedCount = blockElements();
updateStatistics();
return blockedCount;
}
// ==================== 预览功能 ====================
// 预览当前规则 - 临时拦截
function previewCurrentRule() {
if (!STATE.currentSelector) {
showToast('请先选择元素', 'warning');
return;
}
console.log('预览选择器:', STATE.currentSelector);
// 清除之前的预览
clearPreview();
clearTemporaryBlocking();
const testResult = testSelector(STATE.currentSelector);
if (!testResult.valid) {
showToast(`选择器无效: ${testResult.error}`, 'error');
console.error('选择器无效:', testResult.error);
return;
}
if (testResult.count === 0) {
showToast('未匹配到任何元素', 'warning');
console.log('选择器未匹配到元素:', STATE.currentSelector);
return;
}
STATE.isPreviewMode = true;
STATE.isTemporaryBlocking = true; // 启用临时拦截
console.log(`找到 ${testResult.count} 个匹配元素`);
// 高亮所有匹配的元素并临时拦截
testResult.elements.forEach((element, index) => {
try {
element.classList.add('preview-highlight');
// 应用临时拦截
element.classList.add('element-blocked');
element.classList.add('temporary-blocked');
STATE.temporaryBlockedElements.push(element);
console.log(`高亮并临时拦截元素 ${index + 1}:`, element.tagName, element.className);
} catch (e) {
console.error(`高亮元素失败 ${index + 1}:`, e);
}
});
updateBlockedCount();
showToast(`预览中,临时拦截了 ${testResult.count} 个元素`, 'success');
vibrate('success');
// 自动清除预览
setTimeout(() => {
if (STATE.isPreviewMode) {
clearPreview();
clearTemporaryBlocking();
showToast('预览已自动清除', 'info');
}
}, CONFIG.behavior.previewDuration);
updateStatusIndicators();
// 更新元素匹配数量显示
const matchCountElement = document.getElementById('element-match-count');
if (matchCountElement) {
matchCountElement.textContent = testResult.count;
matchCountElement.style.color = testResult.count > 0 ? CONFIG.colors.success : CONFIG.colors.error;
}
}
// 清除预览 - 同时清除临时拦截
function clearPreview() {
if (!STATE.isPreviewMode) return;
console.log('清除预览高亮');
STATE.isPreviewMode = false;
STATE.isTemporaryBlocking = false;
try {
const previewElements = document.querySelectorAll('.preview-highlight');
previewElements.forEach(element => {
element.classList.remove('preview-highlight');
});
console.log(`移除了 ${previewElements.length} 个预览高亮`);
} catch (e) {
console.error('清除预览高亮时出错:', e);
}
clearTemporaryBlocking();
updateStatusIndicators();
}
// 清除临时拦截
function clearTemporaryBlocking() {
console.log('清除临时拦截');
STATE.temporaryBlockedElements.forEach(element => {
try {
element.classList.remove('temporary-blocked');
// 只有没有永久拦截时才移除element-blocked
if (!element.classList.contains('permanent-blocked')) {
element.classList.remove('element-blocked');
}
} catch (e) {
console.error('清除临时拦截失败:', e);
}
});
STATE.temporaryBlockedElements = [];
updateBlockedCount();
}
// ==================== 移动端UI ====================
// 创建移动端UI元素
function createMobileUI() {
// 创建悬浮按钮 - 初始不显示
if (!STATE.elements.floatingBtn) {
const floatingBtn = document.createElement('button');
floatingBtn.id = 'marker-floating-btn';
floatingBtn.innerHTML = '🎯';
floatingBtn.title = '打开标记菜单';
floatingBtn.addEventListener('click', showMenu);
document.body.appendChild(floatingBtn);
STATE.elements.floatingBtn = floatingBtn;
}
// 创建标记模式指示器 - 根据设置决定是否创建
if (STATE.settings.showMarkerHint) {
if (!document.getElementById('marker-mobile-indicator')) {
const indicator = document.createElement('div');
indicator.id = 'marker-mobile-indicator';
indicator.className = 'marker-indicator';
indicator.textContent = '标记模式已激活 - 点击或长按页面元素进行标记';
document.body.appendChild(indicator);
}
} else {
// 如果设置不显示提示,则移除已存在的指示器
const existingIndicator = document.getElementById('marker-mobile-indicator');
if (existingIndicator) {
existingIndicator.remove();
}
}
// 创建长按标记指示器
if (!document.getElementById('long-press-indicator')) {
const indicator = document.createElement('div');
indicator.id = 'long-press-indicator';
indicator.className = 'long-press-indicator';
indicator.textContent = '长按元素进行标记';
document.body.appendChild(indicator);
}
// 创建长按提示
if (!document.getElementById('long-press-hint')) {
const hint = document.createElement('div');
hint.id = 'long-press-hint';
hint.className = 'long-press-hint';
hint.textContent = '长按元素进行标记';
document.body.appendChild(hint);
}
}
// 显示悬浮按钮
function showFloatingButton() {
if (STATE.elements.floatingBtn) {
STATE.elements.floatingBtn.classList.add('visible');
}
}
// 隐藏悬浮按钮
function hideFloatingButton() {
if (STATE.elements.floatingBtn) {
STATE.elements.floatingBtn.classList.remove('visible');
}
}
// 显示标记模式指示器
function showMarkerIndicator() {
if (!STATE.settings.showMarkerHint) return;
const indicator = document.getElementById('marker-mobile-indicator');
if (indicator) {
indicator.classList.add('visible');
} else {
// 如果指示器不存在但设置需要显示,则创建它
const indicator = document.createElement('div');
indicator.id = 'marker-mobile-indicator';
indicator.className = 'marker-indicator';
indicator.textContent = '标记模式已激活 - 点击或长按页面元素进行标记';
indicator.classList.add('visible');
document.body.appendChild(indicator);
}
}
// 隐藏标记模式指示器
function hideMarkerIndicator() {
const indicator = document.getElementById('marker-mobile-indicator');
if (indicator) {
indicator.classList.remove('visible');
}
}
// 创建移动端菜单
function createMobileMenu() {
if (STATE.elements.menu) {
updateMenuContent();
return;
}
const menu = document.createElement('div');
menu.id = 'marker-mobile-menu';
if (STATE.isCompactMode) {
menu.classList.add('compact');
} else {
menu.classList.add('expanded');
}
if (STATE.settings.darkMode) {
menu.classList.add('dark-mode');
}
if (STATE.settings.draggableMenu) {
menu.classList.add('draggable');
}
// 阻止菜单内部触摸事件冒泡
menu.addEventListener('touchstart', function(e) {
e.stopPropagation();
}, { passive: true });
menu.addEventListener('touchend', function(e) {
e.stopPropagation();
}, { passive: true });
loadMenuPositionAndSize(menu);
menu.innerHTML = `