您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced context menu with additional features and customization
// ==UserScript== // @name Enhanced Context Menu // @author ALFHAZERO // @namespace http:// // @version 2.1.1 // @description Enhanced context menu with additional features and customization // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // ==/UserScript== (function() { 'use strict'; /* 1. CONSTANTS & GLOBAL VARIABLES */ const STORAGE_KEYS = { PREFERENCES: 'userPreferences', HIDDEN_ELEMENTS: 'hiddenElements', BOOKMARKS: 'globalBookmarks' }; /* 2. STYLES */ const styles = { contextMenu: { position: 'fixed', backgroundColor: '#ffffff', border: '1px solid #cccccc', borderRadius: '4px', padding: '5px 0', minWidth: '200px', boxShadow: '0 2px 5px rgba(0,0,0,0.2)', zIndex: '9999999', fontSize: '14px', fontFamily: 'Arial, sans-serif' }, menuItem: { padding: '8px 20px', cursor: 'pointer', listStyle: 'none', margin: '0', color: '#333333', transition: 'background-color 0.2s', display: 'flex', alignItems: 'center', gap: '8px' }, divider: { height: '1px', backgroundColor: '#e0e0e0', margin: '5px 0' } }; /* 3. DEFAULT PREFERENCES */ const defaultPreferences = { showBookmark: true, showShare: true, showOpen: true, showViewImage: true, showHideElement: true, showSaveImage: true, showReload: true, showPrint: true, showOpenInNewTab: true, showCopyOptions: true, menuPosition: 'right', darkMode: false, fontSize: 'normal', menuStyle: 'default', menuAnimation: true, menuTransparency: 1, timeoutDuration: 3000, vibrateOnLongPress: true, swipeGestures: true, longPressDelay: 500, preventDefaultContextMenu: true, touchMoveThreshold: 10 }; /* 4. GLOBAL VARIABLES */ let userPreferences = { ...defaultPreferences }; let hiddenElements = []; let globalBookmarks = []; /* 5. UTILITY FUNCTIONS */ function applyStyles(element, styleObject) { Object.assign(element.style, styleObject); } function removeContextMenu() { const existingMenu = document.querySelector('.context-menu'); if (existingMenu) { existingMenu.remove(); } } function vibrate(duration = 50) { if (userPreferences.vibrateOnLongPress && navigator.vibrate) { navigator.vibrate(duration); } } async function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); showNotification('Berhasil disalin!'); } catch (err) { // Fallback method for browsers that don't support clipboard API const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); try { document.execCommand('copy'); showNotification('Berhasil disalin!'); } catch (e) { showNotification('Gagal menyalin teks'); } document.body.removeChild(textarea); } } function showNotification(message, duration = 2000) { const notification = document.createElement('div'); applyStyles(notification, { position: 'fixed', bottom: '20px', left: '50%', transform: 'translateX(-50%)', backgroundColor: 'rgba(0, 0, 0, 0.8)', color: '#ffffff', padding: '10px 20px', borderRadius: '4px', zIndex: '10000', transition: 'opacity 0.3s' }); notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.style.opacity = '0'; setTimeout(() => notification.remove(), 300); }, duration); } function getSelectedText() { const selection = window.getSelection(); return selection ? selection.toString().trim() : ''; } function getLinkUrl(element) { const linkElement = element.closest('a') || (element.tagName === 'A' ? element : null); return linkElement ? linkElement.href : null; } function getImageUrl(element) { if (element.tagName === 'IMG') { return element.src; } else if (element.style.backgroundImage) { const match = element.style.backgroundImage.match(/url\(['"]?([^'"]+)['"]?\)/); return match ? match[1] : null; } return null; } function getElementText(element) { // Get only the text directly contained by this element, excluding child elements let text = ''; for (let node of element.childNodes) { if (node.nodeType === Node.TEXT_NODE) { text += node.textContent.trim(); } } return text || element.innerText.trim() || ''; } /* 6. MANAGER FUNCTIONS */ function createBookmarkManager() { removeContextMenu(); const manager = document.createElement('div'); applyStyles(manager, { position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', backgroundColor: userPreferences.darkMode ? '#333' : '#fff', color: userPreferences.darkMode ? '#fff' : '#333', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)', zIndex: '10000', maxWidth: '80%', maxHeight: '80vh', overflow: 'auto' }); const title = document.createElement('h3'); title.textContent = 'Bookmark Manager'; title.style.marginTop = '0'; manager.appendChild(title); const closeBtn = document.createElement('button'); closeBtn.textContent = '×'; applyStyles(closeBtn, { position: 'absolute', right: '10px', top: '10px', border: 'none', background: 'none', fontSize: '20px', cursor: 'pointer', color: userPreferences.darkMode ? '#fff' : '#333' }); closeBtn.onclick = () => manager.remove(); manager.appendChild(closeBtn); if (globalBookmarks.length === 0) { const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'Tidak ada bookmark'; manager.appendChild(emptyMsg); } else { const list = document.createElement('ul'); applyStyles(list, { listStyle: 'none', padding: '0', margin: '0' }); globalBookmarks.forEach((bookmark, index) => { const item = document.createElement('li'); applyStyles(item, { padding: '10px', borderBottom: '1px solid ' + (userPreferences.darkMode ? '#555' : '#eee'), display: 'flex', justifyContent: 'space-between', alignItems: 'center' }); const link = document.createElement('a'); link.href = bookmark.url; link.textContent = bookmark.title; link.target = '_blank'; applyStyles(link, { color: userPreferences.darkMode ? '#fff' : '#333', textDecoration: 'none' }); const deleteBtn = document.createElement('button'); deleteBtn.textContent = 'Hapus'; applyStyles(deleteBtn, { padding: '5px 10px', border: 'none', borderRadius: '4px', backgroundColor: '#ff4444', color: '#fff', cursor: 'pointer' }); deleteBtn.onclick = () => { globalBookmarks.splice(index, 1); saveAllData(); item.remove(); if (globalBookmarks.length === 0) { manager.querySelector('ul').remove(); const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'Tidak ada bookmark'; manager.appendChild(emptyMsg); } }; item.appendChild(link); item.appendChild(deleteBtn); list.appendChild(item); }); manager.appendChild(list); } document.body.appendChild(manager); } function createHiddenElementsManager() { removeContextMenu(); const manager = document.createElement('div'); applyStyles(manager, { position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', backgroundColor: userPreferences.darkMode ? '#333' : '#fff', color: userPreferences.darkMode ? '#fff' : '#333', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 10px rgba(0,0,0,0.2)', zIndex: '10000', maxWidth: '80%', maxHeight: '80vh', overflow: 'auto' }); const title = document.createElement('h3'); title.textContent = 'Hidden Elements Manager'; title.style.marginTop = '0'; manager.appendChild(title); const closeBtn = document.createElement('button'); closeBtn.textContent = '×'; applyStyles(closeBtn, { position: 'absolute', right: '10px', top: '10px', border: 'none', background: 'none', fontSize: '20px', cursor: 'pointer', color: userPreferences.darkMode ? '#fff' : '#333' }); closeBtn.onclick = () => manager.remove(); manager.appendChild(closeBtn); if (hiddenElements.length === 0) { const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'Tidak ada elemen tersembunyi'; manager.appendChild(emptyMsg); } else { const list = document.createElement('ul'); applyStyles(list, { listStyle: 'none', padding: '0', margin: '0' }); hiddenElements.forEach((selector, index) => { const item = document.createElement('li'); applyStyles(item, { padding: '10px', borderBottom: '1px solid ' + (userPreferences.darkMode ? '#555' : '#eee'), display: 'flex', justifyContent: 'space-between', alignItems: 'center' }); const text = document.createElement('span'); text.textContent = selector; const showBtn = document.createElement('button'); showBtn.textContent = 'Tampilkan'; applyStyles(showBtn, { padding: '5px 10px', border: 'none', borderRadius: '4px', backgroundColor: '#4CAF50', color: '#fff', cursor: 'pointer', marginRight: '5px' }); showBtn.onclick = () => { try { const elements = document.querySelectorAll(selector); elements.forEach(el => { el.style.display = ''; }); hiddenElements.splice(index, 1); saveAllData(); item.remove(); if (hiddenElements.length === 0) { manager.querySelector('ul').remove(); const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'Tidak ada elemen tersembunyi'; manager.appendChild(emptyMsg); } } catch (e) { console.error('Error showing element:', e); } }; item.appendChild(text); item.appendChild(showBtn); list.appendChild(item); }); manager.appendChild(list); } document.body.appendChild(manager); } /* 7. CONTEXT MENU CREATION */ function createContextMenu(target, x, y) { removeContextMenu(); const menu = document.createElement('ul'); menu.className = 'context-menu'; applyStyles(menu, { ...styles.contextMenu, ...(userPreferences.darkMode ? { backgroundColor: '#333333', border: '1px solid #555555', color: '#ffffff' } : {}), opacity: userPreferences.menuTransparency }); // Menu Items Array const menuItems = []; // Copy Options const selectedText = getSelectedText(); if (selectedText) { menuItems.push({ text: 'Salin Teks Terpilih', icon: '📋', action: () => copyToClipboard(selectedText) }); } // Get element text (excluding child elements) const elementText = getElementText(target); if (elementText && elementText !== selectedText) { menuItems.push({ text: 'Salin Teks Elemen', icon: '📝', action: () => copyToClipboard(elementText) }); } // Image Options const imageUrl = getImageUrl(target); if (imageUrl) { if (userPreferences.showViewImage) { menuItems.push({ text: 'Lihat Gambar', icon: '🖼️', action: () => window.open(imageUrl, '_blank') }); } if (userPreferences.showSaveImage) { menuItems.push({ text: 'Simpan Gambar', icon: '💾', action: () => { const link = document.createElement('a'); link.href = imageUrl; link.download = imageUrl.split('/').pop() || 'image'; link.click(); } }); } menuItems.push({ text: 'Salin URL Gambar', icon: '🔗', action: () => copyToClipboard(imageUrl) }); } // Link Options const linkUrl = getLinkUrl(target); if (linkUrl) { menuItems.push({ text: 'Salin Link', icon: '🔗', action: () => copyToClipboard(linkUrl) }); if (userPreferences.showOpenInNewTab) { menuItems.push({ text: 'Buka di Tab Baru', icon: '📑', action: () => window.open(linkUrl, '_blank') }); } } // Standard Menu Items if (userPreferences.showBookmark) { menuItems.push({ text: 'Bookmark', icon: '⭐', action: () => { const url = imageUrl || linkUrl || window.location.href; const title = elementText || document.title; globalBookmarks.push({ url, title }); saveAllData(); showNotification('Bookmark ditambahkan!'); } }); } if (userPreferences.showShare) { menuItems.push({ text: 'Bagikan', icon: '📤', action: () => { const url = imageUrl || linkUrl || window.location.href; if (navigator.share) { navigator.share({ title: document.title, url: url }).catch(console.error); } else { copyToClipboard(url); } } }); } if (userPreferences.showHideElement) { menuItems.push({ text: 'Sembunyikan Elemen', icon: '👁️', action: () => { target.style.display = 'none'; const selector = target.tagName.toLowerCase() + (target.className ? '.' + target.className.replace(/\s+/g, '.') : ''); hiddenElements.push(selector); saveAllData(); showNotification('Elemen disembunyikan!'); } }); } // Management Options menuItems.push({ text: 'Kelola Bookmark', icon: '📚', action: () => createBookmarkManager() }); menuItems.push({ text: 'Kelola Elemen Tersembunyi', icon: '👁️', action: () => createHiddenElementsManager() }); if (userPreferences.showReload) { menuItems.push({ text: 'Muat Ulang', icon: '🔄', action: () => location.reload() }); } // Create Menu Items menuItems.forEach((item, index) => { if (index > 0) { const divider = document.createElement('li'); applyStyles(divider, styles.divider); menu.appendChild(divider); } const menuItem = document.createElement('li'); applyStyles(menuItem, styles.menuItem); menuItem.innerHTML = `<span class="menu-icon">${item.icon}</span><span>${item.text}</span>`; if (userPreferences.darkMode) { menuItem.style.color = '#ffffff'; } menuItem.addEventListener('mouseover', () => { menuItem.style.backgroundColor = userPreferences.darkMode ? '#444444' : '#f0f0f0'; }); menuItem.addEventListener('mouseout', () => { menuItem.style.backgroundColor = 'transparent'; }); menuItem.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); item.action(); removeContextMenu(); }); menu.appendChild(menuItem); }); // Position Menu const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const menuWidth = 200; // Estimated menu width const menuHeight = menuItems.length * 40; // Estimated menu height let posX = x; let posY = y; // Check horizontal position if (x + menuWidth > viewportWidth) { posX = viewportWidth - menuWidth - 10; } // Check vertical position if (y + menuHeight > viewportHeight) { posY = viewportHeight - menuHeight - 10; } applyStyles(menu, { left: posX + 'px', top: posY + 'px' }); document.body.appendChild(menu); // Auto hide menu after timeout if (userPreferences.timeoutDuration > 0) { setTimeout(() => { if (document.body.contains(menu)) { menu.style.opacity = '0'; setTimeout(() => removeContextMenu(), 300); } }, userPreferences.timeoutDuration); } return menu; } /* 8. LONG PRESS HANDLER */ function setupLongPress(element) { if (element.hasAttribute('data-longpress-initialized')) return; let timeoutId; let startX, startY; let isLongPress = false; const moveThreshold = userPreferences.touchMoveThreshold; const startLongPress = (e) => { const coords = e.type.includes('touch') ? { x: e.touches[0].clientX, y: e.touches[0].clientY } : { x: e.clientX, y: e.clientY }; startX = coords.x; startY = coords.y; isLongPress = false; timeoutId = setTimeout(() => { isLongPress = true; vibrate(); createContextMenu(e.target, coords.x, coords.y); }, userPreferences.longPressDelay); }; const moveHandler = (e) => { if (!timeoutId) return; const coords = e.type.includes('touch') ? { x: e.touches[0].clientX, y: e.touches[0].clientY } : { x: e.clientX, y: e.clientY }; if (Math.abs(coords.x - startX) > moveThreshold || Math.abs(coords.y - startY) > moveThreshold) { clearTimeout(timeoutId); timeoutId = null; } }; const endLongPress = (e) => { clearTimeout(timeoutId); if (!isLongPress) return true; e.preventDefault(); return false; }; // Touch Events element.addEventListener('touchstart', startLongPress, { passive: true }); element.addEventListener('touchmove', moveHandler, { passive: true }); element.addEventListener('touchend', endLongPress); element.addEventListener('touchcancel', endLongPress); // Mouse Events element.addEventListener('mousedown', startLongPress); element.addEventListener('mousemove', moveHandler); element.addEventListener('mouseup', endLongPress); element.addEventListener('mouseleave', endLongPress); // Context Menu Prevention if (userPreferences.preventDefaultContextMenu) { element.addEventListener('contextmenu', (e) => e.preventDefault()); } element.setAttribute('data-longpress-initialized', 'true'); } /* 9. INITIALIZATION AND SETUP */ function setupGlobalEvents() { document.addEventListener('click', (e) => { const contextMenu = document.querySelector('.context-menu'); if (contextMenu && !contextMenu.contains(e.target)) { removeContextMenu(); } }); document.addEventListener('scroll', () => { removeContextMenu(); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { removeContextMenu(); } }); } /* 10. STORAGE FUNCTIONS */ function loadAllData() { try { const savedPreferences = GM_getValue(STORAGE_KEYS.PREFERENCES); if (savedPreferences) { userPreferences = { ...defaultPreferences, ...JSON.parse(savedPreferences) }; } const savedHiddenElements = GM_getValue(STORAGE_KEYS.HIDDEN_ELEMENTS); if (savedHiddenElements) { hiddenElements = JSON.parse(savedHiddenElements); } const savedBookmarks = GM_getValue(STORAGE_KEYS.BOOKMARKS); if (savedBookmarks) { globalBookmarks = JSON.parse(savedBookmarks); } } catch (e) { console.error('Error loading data:', e); } } function saveAllData() { try { GM_setValue(STORAGE_KEYS.PREFERENCES, JSON.stringify(userPreferences)); GM_setValue(STORAGE_KEYS.HIDDEN_ELEMENTS, JSON.stringify(hiddenElements)); GM_setValue(STORAGE_KEYS.BOOKMARKS, JSON.stringify(globalBookmarks)); } catch (e) { console.error('Error saving data:', e); } } /* 11. INITIALIZATION */ function init() { loadAllData(); setupGlobalEvents(); const supportedElements = [ 'a', 'img', 'video', '[style*="background-image"]', '.product__sidebar__view__item', 'div', 'span', 'p', 'article', 'section', '.clickable', '[role="button"]', 'button', 'input[type="button"]', 'input[type="submit"]', 'iframe' ]; supportedElements.forEach(selector => { document.querySelectorAll(selector).forEach(el => { if (!el.hasAttribute('data-longpress-initialized')) { setupLongPress(el); } }); }); // Apply hidden elements hiddenElements.forEach(selector => { try { document.querySelectorAll(selector).forEach(el => { el.style.display = 'none'; }); } catch (e) { console.error('Error applying hidden element:', e); } }); // Auto save data every 5 minutes setInterval(saveAllData, 300000); } // Start initialization if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // Cleanup on page unload window.addEventListener('unload', saveAllData); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址