1/** 2 * å¤å¶ä¿æ¤æ¨¡å 3 * æä»¶: js/copy-guard.js 4 * åè½ï¼éå¶ç¨æ·æ¯æ¬¡åªè½å¤å¶ä¸ä¸ªæ®µè½çå 容ï¼é²æ¢å¤§èå´å¤å¶ 5 */ 6 7(function() { 8 'use strict'; 9 10 if (window._copyGuardLoaded) return; 11 window._copyGuardLoaded = true; 12 13 console.log('å¤å¶ä¿æ¤æ¨¡åå·²å è½½'); 14 15 /** 16 * æ ååææ¬ï¼å»é¤å¤ä½ç©ºç½ï¼ 17 */ 18 function normalizeText(txt) { 19 if (!txt) return ''; 20 return txt.replace(/\s+/g, ' ').trim(); 21 } 22 23 /** 24 * å¤ææ®µè½ææ¬æ¯å¦å å«éä¸ææ¬ 25 */ 26 function isTextContained(paraText, selectedText) { 27 var pNorm = normalizeText(paraText); 28 var sNorm = normalizeText(selectedText); 29 if (sNorm.length === 0) return true; 30 if (pNorm.length === 0) return false; 31 // æ£æ¥éä¸ææ¬æ¯å¦å¨æ®µè½ææ¬ä¸ 32 return pNorm.indexOf(sNorm) !== -1; 33 } 34 35 /** 36 * æ¾ç¤ºå¤å¶æç¤º 37 */ 38 function showCopyTip(message) { 39 var oldTip = document.querySelector('.copy-tip'); 40 if (oldTip) oldTip.remove(); 41 42 var tip = document.createElement('div'); 43 tip.className = 'copy-tip'; 44 tip.textContent = message; 45 document.body.appendChild(tip); 46 setTimeout(function() { if (tip.parentNode) tip.remove(); }, 1500); 47 } 48 49 /** 50 * å¤å¶äºä»¶å¤çå¨ 51 */ 52 function paragraphCopyHandler(e) { 53 var sel = window.getSelection(); 54 var selectedText = sel.toString(); 55 56 if (!selectedText || selectedText.length === 0) { 57 return; 58 } 59 60 // è·åéä¸å 容çèµ·å§åç»æå®¹å¨ 61 if (sel.rangeCount === 0) return; 62 var range = sel.getRangeAt(0); 63 64 // æ¥æ¾èµ·å§åç»ææ®µè½ 65 function findParaNode(node) { 66 var el = node.nodeType === 3 ? node.parentNode : node; 67 while (el && el !== document.body && el !== document.getElementById('webBrowser')) { 68 if (el.hasAttribute && el.hasAttribute('data-para-id')) { 69 return el; 70 } 71 el = el.parentNode; 72 } 73 return null; 74 } 75 76 var startPara = findParaNode(range.startContainer); 77 var endPara = findParaNode(range.endContainer); 78 79 // å¦æè·¨æ®µè½ï¼èµ·å§åç»ææ®µè½ä¸åï¼ï¼éå¶å¤å¶ 80 if (startPara && endPara && startPara !== endPara) { 81 e.preventDefault(); 82 e.stopPropagation(); 83 84 // æ¾ç¤ºæç¤º 85 showCopyTip('åªè½å¤å¶å个段è½çå 容'); 86 87 // èªå¨éæ©èµ·å§æ®µè½ 88 sel.removeAllRanges(); 89 var newRange = document.createRange(); 90 newRange.selectNodeContents(startPara); 91 sel.addRange(newRange); 92 93 // å»¶è¿æ§è¡å¤å¶ 94 setTimeout(function() { 95 try { 96 document.execCommand('copy'); 97 console.log('å·²èªå¨å¤å¶å½å段è½'); 98 } catch(err) { 99 console.warn('å¤å¶å¤±è´¥:', err); 100 } 101 }, 50); 102 return; 103 } 104 105 // å¦ææ²¡ææ¾å°æ®µè½æ è¯ï¼æè å¨å䏿®µè½å ï¼å 许æ£å¸¸å¤å¶ 106 console.log('æ£å¸¸å¤å¶ï¼é䏿æ¬é¿åº¦:', selectedText.length); 107 } 108 109 /** 110 * 为ææåä¿æ¤æ®µè½éå çå¬å¨ 111 */ 112 function attachCopyListeners() { 113 var paras = document.querySelectorAll('[data-para-id]'); 114 for (var i = 0; i < paras.length; i++) { 115 var p = paras[i]; 116 p.removeEventListener('copy', paragraphCopyHandler); 117 p.removeEventListener('cut', paragraphCopyHandler); 118 p.addEventListener('copy', paragraphCopyHandler); 119 p.addEventListener('cut', paragraphCopyHandler); 120 } 121 122 if (paras.length > 0) { 123 console.log('已为 ' + paras.length + ' 个段è½éå å¤å¶ä¿æ¤çå¬å¨'); 124 } 125 } 126 127 /** 128 * ç¦ç¨å ¨éåè½ï¼Ctrl+Aï¼ 129 */ 130 function disableSelectAll() { 131 document.addEventListener('keydown', function(e) { 132 if (e.ctrlKey && e.key === 'a') { 133 e.preventDefault(); 134 showCopyTip('请æå¨éæ©è¦å¤å¶ç段è½'); 135 136 // å¯éï¼èªå¨éæ©ç¬¬ä¸ä¸ªæ®µè½ 137 var firstPara = document.querySelector('[data-para-id]'); 138 if (firstPara) { 139 var sel = window.getSelection(); 140 sel.removeAllRanges(); 141 var range = document.createRange(); 142 range.selectNodeContents(firstPara); 143 sel.addRange(range); 144 } 145 } 146 }); 147 } 148 149 /** 150 * åå§åå¤å¶ä¿æ¤ 151 */ 152 function initCopyGuard() { 153 // å»¶è¿æ§è¡ï¼çå¾ DOMå è½½ 154 setTimeout(function() { 155 attachCopyListeners(); 156 disableSelectAll(); 157 }, 200); 158 159 // ä½¿ç¨ MutationObserver çå¬å¨ææ·»å çå 容 160 var observer = new MutationObserver(function(mutations) { 161 var needAttach = false; 162 for (var i = 0; i < mutations.length; i++) { 163 if (mutations[i].addedNodes.length > 0) { 164 needAttach = true; 165 break; 166 } 167 } 168 if (needAttach) { 169 setTimeout(attachCopyListeners, 200); 170 } 171 }); 172 173 var targetNode = document.getElementById('webBrowser'); 174 if (targetNode) { 175 observer.observe(targetNode, { childList: true, subtree: true });
176 } 177 178 // 宿鿰éå ï¼ä¿é©æªæ½ï¼ 179 setInterval(attachCopyListeners, 3000); 180 } 181 182 // 页é¢å è½½å®æååå§å 183 if (document.readyState === 'loading') { 184 document.addEventListener('DOMContentLoaded', initCopyGuard); 185 } else { 186 initCopyGuard(); 187 } 188 189 // 导åºå ¨å±æ¹æ³ 190 window.attachCopyListeners = attachCopyListeners; 191 window.reinitCopyGuard = function() { 192 attachCopyListeners(); 193 }; 194 195})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.