您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
모바일 요소 선택기
当前为
// ==UserScript== // @name Mobile Element Selector // @author ZNJXL // @version 1.1.1 // @namespace http://tampermonkey.net/ // @description 모바일 요소 선택기 // @match *://*/* // @license MIT // @grant GM_setClipboard // ==/UserScript== (function() { 'use strict'; let selecting = false; let selectedEl = null; let initialTouchedElement = null; let includeSiteName = false; let touchStartX = 0, touchStartY = 0; let touchMoved = true; const moveThreshold = 10; const style = document.createElement('style'); style.textContent = ` .mobile-block-ui { z-index: 9999 !important; touch-action: manipulation !important; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; box-sizing: border-box; position: fixed; } #blocker-slider { width: 100%; margin: 10px 0; -webkit-appearance: none; appearance: none; background: #555; height: 8px; border-radius: 5px; outline: none; } #blocker-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; background: #4CAF50; border-radius: 50%; cursor: pointer; border: 2px solid #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.3); } #blocker-slider::-moz-range-thumb { width: 20px; height: 20px; background: #4CAF50; border-radius: 50%; cursor: pointer; border: 2px solid #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.3); } .selected-element { background-color: rgba(255, 0, 0, 0.25) !important; z-index: 9998 !important; } #mobile-block-panel { top: calc(100vh - 150px); left: 15px; width: 300px; background: rgba(40, 40, 40, 0.95); color: #eee; padding: 15px; border-radius: 12px; box-shadow: 0 5px 15px rgba(0,0,0,0.6); display: none; z-index: 10001; border-top: 1px solid rgba(255, 255, 255, 0.1); } #mobile-block-toggleBtn { top: 15px; left: 15px; z-index: 10002; background: linear-gradient(145deg, #f44336, #d32f2f); color: #fff; padding: 10px 18px; border-radius: 25px; font-size: 15px; font-weight: 500; border: none; cursor: pointer; box-shadow: 0 4px 10px rgba(0,0,0,0.3); transition: background 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease; min-width: 100px; } #mobile-block-toggleBtn:hover { transform: translateY(-2px); box-shadow: 0 6px 15px rgba(0,0,0,0.4); } #mobile-block-toggleBtn.selecting { background: linear-gradient(145deg, #4CAF50, #388E3C); } .mb-btn { padding: 10px; border: none; border-radius: 8px; color: #fff; font-size: 14px; cursor: pointer; transition: background 0.2s ease, transform 0.1s ease, box-shadow 0.2s ease; background-color: #555; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.2); min-width: 80px; } .mb-btn:active { transform: scale(0.97); box-shadow: inset 0 2px 4px rgba(0,0,0,0.3); } #blocker-copy { background: linear-gradient(145deg, #2196F3, #1976D2); } #blocker-toggle-site { background: linear-gradient(145deg, #9C27B0, #7B1FA2); color: #fff; } #blocker-block { background: linear-gradient(145deg, #f44336, #c62828); } #blocker-cancel { background: linear-gradient(145deg, #607D8B, #455A64); } .button-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); gap: 8px; margin-top: 15px; } #blocker-info-wrapper { position: relative; margin-bottom: 10px; } #blocker-info { display: block; color: #90ee90; font-size: 13px; line-height: 1.4; background-color: rgba(0,0,0,0.3); padding: 5px 8px; border-radius: 4px; word-break: break-all; } `; document.head.appendChild(style); const panel = document.createElement('div'); panel.id = 'mobile-block-panel'; panel.classList.add('mobile-block-ui', 'ui-ignore'); panel.innerHTML = ` <div id="blocker-info-wrapper"> <span style="font-size: 12px; color: #ccc;">선택된 요소:</span> <span id="blocker-info">없음</span> </div> <input type="range" id="blocker-slider" min="0" max="10" value="0" class="ui-ignore"> <div class="button-grid"> <button id="blocker-copy" class="mb-btn ui-ignore">복사</button> <button id="blocker-toggle-site" class="mb-btn ui-ignore">${includeSiteName ? "사이트명: ON" : "사이트명: OFF"}</button> <button id="blocker-block" class="mb-btn ui-ignore">미리보기</button> <button id="blocker-cancel" class="mb-btn ui-ignore">취소</button> </div> `; document.body.appendChild(panel); const toggleBtn = document.createElement('button'); toggleBtn.id = 'mobile-block-toggleBtn'; toggleBtn.classList.add('mobile-block-ui', 'ui-ignore'); toggleBtn.textContent = '차단 모드'; document.body.appendChild(toggleBtn); function setBlockMode(enabled) { selecting = enabled; toggleBtn.textContent = enabled ? '선택 중...' : '차단 모드'; toggleBtn.classList.toggle('selecting', enabled); panel.style.display = enabled ? 'block' : 'none'; if (!enabled && selectedEl) { selectedEl.classList.remove('selected-element'); selectedEl = null; initialTouchedElement = null; } panel.querySelector('#blocker-slider').value = 0; updateInfo(); } function updateInfo() { const infoSpan = panel.querySelector('#blocker-info'); infoSpan.textContent = selectedEl ? generateSelector(selectedEl) : '없음'; } function generateSelector(el) { if (!el || el.nodeType !== 1) return ''; const parts = []; let current = el; const maxDepth = 5; let depth = 0; while (current && current.tagName && current.tagName.toLowerCase() !== 'body' && current.tagName.toLowerCase() !== 'html' && depth < maxDepth) { const parent = current.parentElement; const tagName = current.tagName.toLowerCase(); let selectorPart = tagName; if (current.id) { selectorPart = `#${current.id}`; parts.unshift(selectorPart); depth++; break; } else { const classes = Array.from(current.classList).filter(c => !['selected-element', 'mobile-block-ui', 'ui-ignore'].includes(c)); if (classes.length > 0) { selectorPart = '.' + classes.join('.'); } else if (parent) { const siblings = Array.from(parent.children); let sameTagIndex = 0; let found = false; for (let i = 0; i < siblings.length; i++) { if (siblings[i].tagName === current.tagName) { sameTagIndex++; if (siblings[i] === current) { found = true; break; } } } if (found && sameTagIndex > 0) { selectorPart = `${tagName}:nth-of-type(${sameTagIndex})`; } } parts.unshift(selectorPart); depth++; } if (!parent || parent.tagName.toLowerCase() === 'body' || parent.tagName.toLowerCase() === 'html') break; current = parent; } return parts.join(' > '); } const uiExcludeClass = '.ui-ignore'; document.addEventListener('touchstart', e => { if (!selecting || e.target.closest(uiExcludeClass)) return; const touch = e.touches[0]; touchStartX = touch.clientX; touchStartY = touch.clientY; touchMoved = false; }, { passive: true }); document.addEventListener('touchmove', e => { if (!selecting || e.target.closest(uiExcludeClass) || !e.touches[0]) return; if (!touchMoved) { const touch = e.touches[0]; const dx = touch.clientX - touchStartX, dy = touch.clientY - touchStartY; if (Math.sqrt(dx * dx + dy * dy) > moveThreshold) touchMoved = true; } }, { passive: true }); document.addEventListener('touchend', e => { if (!selecting || e.target.closest(uiExcludeClass)) return; if (touchMoved) { touchMoved = false; return; } e.preventDefault(); e.stopImmediatePropagation(); const touch = e.changedTouches[0]; const targetEl = document.elementFromPoint(touch.clientX, touch.clientY); if (!targetEl || targetEl.closest(uiExcludeClass)) return; if (selectedEl) selectedEl.classList.remove('selected-element'); selectedEl = targetEl; initialTouchedElement = targetEl; selectedEl.classList.add('selected-element'); panel.querySelector('#blocker-slider').value = 0; updateInfo(); }, { capture: true, passive: false }); const slider = panel.querySelector('#blocker-slider'); slider.addEventListener('input', handleSlider); function handleSlider(e) { if (!initialTouchedElement) return; const level = parseInt(e.target.value, 10); let current = initialTouchedElement; for (let i = 0; i < level && current.parentElement; i++) { if (current.parentElement.tagName.toLowerCase() === 'body' || current.parentElement.tagName.toLowerCase() === 'html') break; current = current.parentElement; } if (selectedEl) selectedEl.classList.remove('selected-element'); selectedEl = current; selectedEl.classList.add('selected-element'); updateInfo(); } panel.querySelector('#blocker-copy').addEventListener('click', () => { if (selectedEl) { const fullSelector = generateSelector(selectedEl); let finalSelector = "##" + fullSelector; if (includeSiteName) finalSelector = location.hostname + finalSelector; try { GM_setClipboard(finalSelector); alert('✅ 선택자가 복사되었습니다!\n' + finalSelector); } catch (err) { console.error("클립보드 복사 실패:", err); alert("❌ 클립보드 복사에 실패했습니다."); prompt("선택자를 직접 복사하세요:", finalSelector); } } else { alert('선택된 요소가 없습니다.'); } }); panel.querySelector('#blocker-toggle-site').addEventListener('click', () => { includeSiteName = !includeSiteName; panel.querySelector('#blocker-toggle-site').textContent = includeSiteName ? "사이트명: ON" : "사이트명: OFF"; }); const blockBtn = panel.querySelector('#blocker-block'); let isHidden = false; blockBtn.textContent = '미리보기'; blockBtn.addEventListener('click', () => { if (!selectedEl) { alert('선택된 요소가 없습니다.'); return; } if (!isHidden) { selectedEl.dataset._original_display = selectedEl.style.display || ''; selectedEl.style.display = 'none'; blockBtn.textContent = '되돌리기'; isHidden = true; } else { selectedEl.style.display = selectedEl.dataset._original_display || ''; blockBtn.textContent = '미리보기'; isHidden = false; } }); panel.querySelector('#blocker-cancel').addEventListener('click', () => setBlockMode(false)); toggleBtn.addEventListener('click', () => setBlockMode(!selecting)); function makeDraggable(el) { let startX, startY, origX, origY; let dragging = false, moved = false; el.addEventListener('touchstart', function(e) { if (e.target.tagName.toLowerCase() === 'input') return; startX = e.touches[0].clientX; startY = e.touches[0].clientY; const rect = el.getBoundingClientRect(); origX = rect.left; origY = rect.top; dragging = true; moved = false; }, {passive: true}); el.addEventListener('touchmove', function(e) { if (!dragging) return; const dx = e.touches[0].clientX - startX; const dy = e.touches[0].clientY - startY; if (Math.sqrt(dx * dx + dy * dy) > moveThreshold) { moved = true; el.style.left = (origX + dx) + 'px'; el.style.top = (origY + dy) + 'px'; el.style.right = 'auto'; el.style.bottom = 'auto'; e.preventDefault(); } }, {passive: false}); el.addEventListener('touchend', function(e) { dragging = false; if(moved) { e.preventDefault(); e.stopPropagation(); } }, {passive: false}); } makeDraggable(panel); makeDraggable(toggleBtn); })();