שיתוף | סקריפט לטמפרמונקי להפיכת קישורים לניתנים ללחיצה במערכת הסמסים של וירטואל פלוס
-
לא יודע איך לא חשבתי על זה עד היום..
תמיד הייתי מסמן את הקישור ולוחץ לחיצה ימנית, מעבר אל,
הבעיה מתחילה כשהקישורים ארוכים יותר משורה אחת..
שאז הוא כן תופס הכל או לא תופס הכל...
אז פניתי ל AI וביקשתי ממנו לכתוב סקריפט לטמפרמונקי שיהפוך את הקישורים מטקסט פשוט ל"קישורים"
תהנו:// ==UserScript== // @name הפיכת קישורים לניתנים ללחיצה במערכת הסמסים של וירטואל פלוס // @namespace http://tampermonkey.net/ // @version 4.0 // @description הופך URL/Email/טלפון/קודי OTP/Tracking ללחיצים ומוסיף כפתור העתקה בהובר בלבד, בלי כפילויות // @author שאול 208 // @match https://www.call2all.co.il/ym/index.php?view=Incoming_sms // @grant none // ==/UserScript== (function() { 'use strict'; // ===== CSS ===== const style = document.createElement('style'); style.textContent = ` .copy-wrap{display:inline-flex;align-items:center;gap:4px} .copy-btn{display:none;border:0;background:transparent;cursor:pointer;font-size:.8em} .copy-wrap:hover .copy-btn{display:inline} .code-strong{font-weight:700} a { color: blue; text-decoration: underline; } `; document.head.appendChild(style); // ===== Regexים ===== const urlRegex = /\b((https?:\/\/|www\.)[^\s<]+)/gi; const emailRegex = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi; const phoneRegex = /\b972\d{8,9}\b/g; // טלפון ישראלי const otpRegex = /\b\d{4,8}\b/g; // קוד אימות 4–8 ספרות const trackingRegex = /\b(?=[A-Z0-9]{6,20}\b)(?=.*\d)(?=.*[A-Z])[A-Z0-9]+\b/gi; // ===== עזר ===== function createCopyButton(text) { const btn = document.createElement('button'); btn.className = 'copy-btn'; btn.type = 'button'; btn.title = 'העתקה'; btn.textContent = '📋'; btn.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); navigator.clipboard.writeText(text).then(() => { const old = btn.textContent; btn.textContent = '✅'; setTimeout(() => btn.textContent = old, 900); }); }); return btn; } function buildWrap(el, copyText) { const wrap = document.createElement('span'); wrap.className = 'copy-wrap'; wrap.appendChild(el); wrap.appendChild(createCopyButton(copyText)); return wrap; } function augmentAnchors(root) { root.querySelectorAll('a').forEach(a => { if (a.closest('.copy-wrap')) return; const copyText = (a.textContent || a.getAttribute('href') || '').trim(); const wrap = document.createElement('span'); wrap.className = 'copy-wrap'; a.replaceWith(wrap); wrap.appendChild(a); wrap.appendChild(createCopyButton(copyText)); }); } function hasOverlap(start, end, ranges) { return ranges.some(([s, e]) => !(end <= s || start >= e)); } function addRange(start, end, ranges) { ranges.push([start, end]); } function collectMatches(text) { const matches = []; const taken = []; function addByRegex(regex, type, build) { regex.lastIndex = 0; let m; while ((m = regex.exec(text)) !== null) { const start = m.index; const end = start + m[0].length; if (!hasOverlap(start, end, taken)) { matches.push(build(m, start, end, type)); addRange(start, end, taken); } } } addByRegex(urlRegex, 'url', (m, start, end) => { const raw = m[1]; const href = raw.startsWith('http') ? raw : 'http://' + raw; return { type: 'url', start, end, text: raw, href }; }); addByRegex(emailRegex, 'email', (m, start, end) => { const mail = m[0]; return { type: 'email', start, end, text: mail, href: 'mailto:' + mail }; }); addByRegex(phoneRegex, 'phone', (m, start, end) => { const phone = m[0]; const href = 'tel:' + phone; return { type: 'phone', start, end, text: phone, href }; }); addByRegex(otpRegex, 'otp', (m, start, end) => { return { type: 'otp', start, end, text: m[0] }; }); addByRegex(trackingRegex, 'tracking', (m, start, end) => { return { type: 'tracking', start, end, text: m[0] }; }); return matches.sort((a,b) => a.start - b.start); } function processTextNode(node) { if (node.parentNode.closest('a')) return; const text = node.textContent; const matches = collectMatches(text); if (!matches.length) return; const frag = document.createDocumentFragment(); let cursor = 0; for (const m of matches) { if (cursor < m.start) frag.appendChild(document.createTextNode(text.slice(cursor, m.start))); if (['url','email','phone'].includes(m.type)) { const a = document.createElement('a'); a.href = m.href; a.textContent = m.text; a.target = '_blank'; a.rel = 'noopener'; frag.appendChild(buildWrap(a, m.text)); } else if (['otp','tracking'].includes(m.type)) { const strong = document.createElement('strong'); strong.className = 'code-strong'; strong.textContent = m.text; frag.appendChild(buildWrap(strong, m.text)); } cursor = m.end; } if (cursor < text.length) frag.appendChild(document.createTextNode(text.slice(cursor))); node.parentNode.replaceChild(frag, node); } function processContainer(root = document) { augmentAnchors(root); const elements = root.querySelectorAll('.sms-message, .message, td, p, span, div'); elements.forEach(el => { if (el.classList.contains('processed')) return; Array.from(el.childNodes).forEach(n => { if (n.nodeType === Node.TEXT_NODE) processTextNode(n); }); el.classList.add('processed'); }); } window.addEventListener('load', () => { processContainer(document); }); const target = document.querySelector('#main-view') || document.body; const observer = new MutationObserver(mutations => { mutations.forEach(m => { m.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) processContainer(node); }); }); }); observer.observe(target, { childList:true, subtree:true }); })();עדכנו אם יש בעיה וכו'
-
לא יודע איך לא חשבתי על זה עד היום..
תמיד הייתי מסמן את הקישור ולוחץ לחיצה ימנית, מעבר אל,
הבעיה מתחילה כשהקישורים ארוכים יותר משורה אחת..
שאז הוא כן תופס הכל או לא תופס הכל...
אז פניתי ל AI וביקשתי ממנו לכתוב סקריפט לטמפרמונקי שיהפוך את הקישורים מטקסט פשוט ל"קישורים"
תהנו:// ==UserScript== // @name הפיכת קישורים לניתנים ללחיצה במערכת הסמסים של וירטואל פלוס // @namespace http://tampermonkey.net/ // @version 4.0 // @description הופך URL/Email/טלפון/קודי OTP/Tracking ללחיצים ומוסיף כפתור העתקה בהובר בלבד, בלי כפילויות // @author שאול 208 // @match https://www.call2all.co.il/ym/index.php?view=Incoming_sms // @grant none // ==/UserScript== (function() { 'use strict'; // ===== CSS ===== const style = document.createElement('style'); style.textContent = ` .copy-wrap{display:inline-flex;align-items:center;gap:4px} .copy-btn{display:none;border:0;background:transparent;cursor:pointer;font-size:.8em} .copy-wrap:hover .copy-btn{display:inline} .code-strong{font-weight:700} a { color: blue; text-decoration: underline; } `; document.head.appendChild(style); // ===== Regexים ===== const urlRegex = /\b((https?:\/\/|www\.)[^\s<]+)/gi; const emailRegex = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi; const phoneRegex = /\b972\d{8,9}\b/g; // טלפון ישראלי const otpRegex = /\b\d{4,8}\b/g; // קוד אימות 4–8 ספרות const trackingRegex = /\b(?=[A-Z0-9]{6,20}\b)(?=.*\d)(?=.*[A-Z])[A-Z0-9]+\b/gi; // ===== עזר ===== function createCopyButton(text) { const btn = document.createElement('button'); btn.className = 'copy-btn'; btn.type = 'button'; btn.title = 'העתקה'; btn.textContent = '📋'; btn.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); navigator.clipboard.writeText(text).then(() => { const old = btn.textContent; btn.textContent = '✅'; setTimeout(() => btn.textContent = old, 900); }); }); return btn; } function buildWrap(el, copyText) { const wrap = document.createElement('span'); wrap.className = 'copy-wrap'; wrap.appendChild(el); wrap.appendChild(createCopyButton(copyText)); return wrap; } function augmentAnchors(root) { root.querySelectorAll('a').forEach(a => { if (a.closest('.copy-wrap')) return; const copyText = (a.textContent || a.getAttribute('href') || '').trim(); const wrap = document.createElement('span'); wrap.className = 'copy-wrap'; a.replaceWith(wrap); wrap.appendChild(a); wrap.appendChild(createCopyButton(copyText)); }); } function hasOverlap(start, end, ranges) { return ranges.some(([s, e]) => !(end <= s || start >= e)); } function addRange(start, end, ranges) { ranges.push([start, end]); } function collectMatches(text) { const matches = []; const taken = []; function addByRegex(regex, type, build) { regex.lastIndex = 0; let m; while ((m = regex.exec(text)) !== null) { const start = m.index; const end = start + m[0].length; if (!hasOverlap(start, end, taken)) { matches.push(build(m, start, end, type)); addRange(start, end, taken); } } } addByRegex(urlRegex, 'url', (m, start, end) => { const raw = m[1]; const href = raw.startsWith('http') ? raw : 'http://' + raw; return { type: 'url', start, end, text: raw, href }; }); addByRegex(emailRegex, 'email', (m, start, end) => { const mail = m[0]; return { type: 'email', start, end, text: mail, href: 'mailto:' + mail }; }); addByRegex(phoneRegex, 'phone', (m, start, end) => { const phone = m[0]; const href = 'tel:' + phone; return { type: 'phone', start, end, text: phone, href }; }); addByRegex(otpRegex, 'otp', (m, start, end) => { return { type: 'otp', start, end, text: m[0] }; }); addByRegex(trackingRegex, 'tracking', (m, start, end) => { return { type: 'tracking', start, end, text: m[0] }; }); return matches.sort((a,b) => a.start - b.start); } function processTextNode(node) { if (node.parentNode.closest('a')) return; const text = node.textContent; const matches = collectMatches(text); if (!matches.length) return; const frag = document.createDocumentFragment(); let cursor = 0; for (const m of matches) { if (cursor < m.start) frag.appendChild(document.createTextNode(text.slice(cursor, m.start))); if (['url','email','phone'].includes(m.type)) { const a = document.createElement('a'); a.href = m.href; a.textContent = m.text; a.target = '_blank'; a.rel = 'noopener'; frag.appendChild(buildWrap(a, m.text)); } else if (['otp','tracking'].includes(m.type)) { const strong = document.createElement('strong'); strong.className = 'code-strong'; strong.textContent = m.text; frag.appendChild(buildWrap(strong, m.text)); } cursor = m.end; } if (cursor < text.length) frag.appendChild(document.createTextNode(text.slice(cursor))); node.parentNode.replaceChild(frag, node); } function processContainer(root = document) { augmentAnchors(root); const elements = root.querySelectorAll('.sms-message, .message, td, p, span, div'); elements.forEach(el => { if (el.classList.contains('processed')) return; Array.from(el.childNodes).forEach(n => { if (n.nodeType === Node.TEXT_NODE) processTextNode(n); }); el.classList.add('processed'); }); } window.addEventListener('load', () => { processContainer(document); }); const target = document.querySelector('#main-view') || document.body; const observer = new MutationObserver(mutations => { mutations.forEach(m => { m.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) processContainer(node); }); }); }); observer.observe(target, { childList:true, subtree:true }); })();עדכנו אם יש בעיה וכו'
שלום! נראה שהשיחה הזו מעניינת אותך, אבל עדיין אין לך חשבון.
נמאס לכם לגלול בין אותם הפוסטים בכל ביקור? כשנרשמים לחשבון, תמיד תחזרו בדיוק למקום שבו הייתם קודם, ותוכלו לבחור לקבל התראות על תגובות חדשות (בין אם במייל, ובין אם בהתראת פוש). תוכלו גם לשמור סימניות ולפרגן ב-upvote לפוסטים כדי להביע הערכה לחברי קהילה אחרים.
בעזרת התרומה שלך, הפוסט הזה יכול להיות אפילו טוב יותר 💗
הרשמה התחברות
)