您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
모바일 요소 선택기
当前为
// ==UserScript== // @name Mobile Element Selector // @author ZNJXL // @version 1.1.3 // @namespace http://tampermonkey.net/ // @description 모바일 요소 선택기 // @description:en Mobile Element Selector (especially for cromium browsers) // @match *://*/* // @license MIT // @grant GM_setClipboard // ==/UserScript== (function() { 'use strict'; let selecting = false; let selectedEl = null; let initialTouchedElement = null; let includeSiteName = true; let touchStartX = 0, touchStartY = 0; let touchMoved = false; const moveThreshold = 10; // 다국어 텍스트 정의 const i18n = { ko: { blockerInfo: "선택된 요소:", blockerCopy: "복사", blockerToggleSite: (siteNameOn) => `사이트명: ${siteNameOn ? "ON" : "OFF"}`, blockerBlock: "미리보기", blockerCancel: "취소", blockerMode: "차단 모드", blockerSelecting: "선택 중...", blockerPreview: "미리보기", blockerRevert: "되돌리기", alertNoElement: "선택된 요소가 없습니다.", alertCopySuccess: "✅ 선택자가 복사되었습니다!", alertCopyFail: "❌ 클립보드 복사에 실패했습니다.", alertDirectCopy: "선택자를 직접 복사하세요:", }, en: { blockerInfo: "Selected Element:", blockerCopy: "Copy", blockerToggleSite: (siteNameOn) => `Site Name: ${siteNameOn ? "ON" : "OFF"}`, blockerBlock: "Preview", blockerCancel: "Cancel", blockerMode: "Block Mode", blockerSelecting: "Selecting...", blockerPreview: "Preview", blockerRevert: "Revert", alertNoElement: "No element selected.", alertCopySuccess: "✅ Selector copied!", alertCopyFail: "❌ Failed to copy to clipboard.", alertDirectCopy: "Copy the selector manually:" } }; // 언어 감지 및 선택 (기본값은 한국어) const lang = navigator.language.startsWith('ko') ? 'ko' : 'en'; const t = i18n[lang]; const style = document.createElement('style'); style.textContent = ` .mobile-block-ui { /* 스타일 내용은 동일 */ } #blocker-slider { /* 스타일 내용은 동일 */ } #blocker-slider::-webkit-slider-thumb { /* 스타일 내용은 동일 */ } #blocker-slider::-moz-range-thumb { /* 스타일 내용은 동일 */ } .selected-element { /* 스타일 내용은 동일 */ } #mobile-block-panel { /* 스타일 내용은 동일 */ } #mobile-block-toggleBtn { /* 스타일 내용은 동일 */ } .mb-btn { /* 스타일 내용은 동일 */ } #blocker-info-wrapper { /* 스타일 내용은 동일 */ } #blocker-info { /* 스타일 내용은 동일 */ } `; 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;">${t.blockerInfo}</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">${t.blockerCopy}</button> <button id="blocker-toggle-site" class="mb-btn ui-ignore">${t.blockerToggleSite(includeSiteName)}</button> <button id="blocker-block" class="mb-btn ui-ignore">${t.blockerBlock}</button> <button id="blocker-cancel" class="mb-btn ui-ignore">${t.blockerCancel}</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 = t.blockerMode; document.body.appendChild(toggleBtn); function setBlockMode(enabled) { selecting = enabled; toggleBtn.textContent = enabled ? t.blockerSelecting : t.blockerMode; 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) { /* generateSelector 함수는 그대로 유지 */ } 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) { /* handleSlider 함수는 그대로 유지 */ } 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(t.alertCopySuccess + '\n' + finalSelector); } catch (err) { console.error("클립보드 복사 실패:", err); alert(t.alertCopyFail); prompt(t.alertDirectCopy, finalSelector); } } else { alert(t.alertNoElement); } }); panel.querySelector('#blocker-toggle-site').addEventListener('click', () => { includeSiteName = !includeSiteName; panel.querySelector('#blocker-toggle-site').textContent = t.blockerToggleSite(includeSiteName); }); const blockBtn = panel.querySelector('#blocker-block'); let isHidden = false; blockBtn.textContent = t.blockerPreview; blockBtn.addEventListener('click', () => { if (!selectedEl) { alert(t.alertNoElement); return; } if (!isHidden) { selectedEl.dataset._original_display = selectedEl.style.display || ''; selectedEl.style.display = 'none'; blockBtn.textContent = t.blockerRevert; isHidden = true; } else { selectedEl.style.display = selectedEl.dataset._original_display || ''; blockBtn.textContent = t.blockerPreview; isHidden = false; } }); panel.querySelector('#blocker-cancel').addEventListener('click', () => setBlockMode(false)); toggleBtn.addEventListener('click', () => setBlockMode(!selecting)); function makeDraggable(el) { /* makeDraggable 함수는 그대로 유지 */ } makeDraggable(panel); makeDraggable(toggleBtn); })();