1(function( $ ) { 2 'use strict'; 3 4 $(document).ready(function() { 5 6 function initCodeHighlighting() { 7 if (typeof Prism !== 'undefined') { 8 setTimeout(function() { 9 Prism.highlightAll(); 10 }, 100); 11 } else { 12 // åºæ¬èªæ³é«äº®åç¨æ¹æ¡ 13 applyBasicHighlighting(); 14 } 15 } 16 17 function applyBasicHighlighting() { 18 $('.wp-block-achang-pencil-box-code-box code').each(function() { 19 var $code = $(this); 20 var text = $code.text(); 21 var className = $code.attr('class') || ''; 22 var languageMatch = className.match(/language-(\w+)/); 23 var language = languageMatch ? languageMatch[1] : 'plaintext'; 24 25 if (language !== 'plaintext') { 26 var highlightedText = basicSyntaxHighlight(text, language); 27 $code.html(highlightedText); 28 } 29 }); 30 } 31 32 function basicSyntaxHighlight(text, language) { 33 // åºæ¬çèªæ³é«äº®å½æ¸ 34 var highlighted = text; 35 36 // JavaScript/TypeScript é«äº® 37 if (language === 'javascript' || language === 'typescript' || language === 'js' || language === 'ts') { 38 highlighted = highlighted 39 .replace(/\b(function|var|let|const|if|else|for|while|return|class|extends|import|export|from|default|async|await|try|catch|finally|throw|new|this|super|static|public|private|protected)\b/g, '<span class="apb-keyword">$1</span>') 40 .replace(/(["'`])((?:\\.|(?!\1)[^\\])*?)\1/g, '<span class="apb-string">$1$2$1</span>') 41 .replace(/\/\/.*$/gm, '<span class="apb-comment">$&</span>') 42 .replace(/\/\*[\s\S]*?\*\//g, '<span class="apb-comment">$&</span>') 43 .replace(/\b(\d+\.?\d*)\b/g, '<span class="apb-number">$1</span>'); 44 } 45 // PHP é«äº® 46 else if (language === 'php') { 47 highlighted = highlighted 48 .replace(/\b(function|class|extends|implements|public|private|protected|static|final|abstract|interface|trait|namespace|use|as|if|else|elseif|endif|for|foreach|endfor|while|endwhile|do|switch|case|default|break|continue|return|try|catch|finally|throw|new|clone|instanceof|echo|print|var|const|global|static|unset|isset|empty|array|object|string|int|float|bool|null|true|false)\b/g, '<span class="apb-keyword">$1</span>') 49 .replace(/(["'`])((?:\\.|(?!\1)[^\\])*?)\1/g, '<span class="apb-string">$1$2$1</span>') 50 .replace(/\/\/.*$/gm, '<span class="apb-comment">$&</span>') 51 .replace(/\/\*[\s\S]*?\*\//g, '<span class="apb-comment">$&</span>') 52 .replace(/#.*$/gm, '<span class="apb-comment">$&</span>') 53 .replace(/\$\w+/g, '<span class="apb-variable">$&</span>') 54 .replace(/\b(\d+\.?\d*)\b/g, '<span class="apb-number">$1</span>'); 55 } 56 // CSS é«äº® 57 else if (language === 'css' || language === 'scss') { 58 highlighted = highlighted 59 .replace(/([.#]?[\w-]+)\s*\{/g, '<span class="apb-selector">$1</span>{') 60 .replace(/([\w-]+)\s*:/g, '<span class="apb-property">$1</span>:') 61 .replace(/:\s*([^;}\n]+)/g, ': <span class="apb-value">$1</span>') 62 .replace(/\/\*[\s\S]*?\*\//g, '<span class="apb-comment">$&</span>'); 63 } 64 // HTML é«äº® 65 else if (language === 'html' || language === 'xml') { 66 highlighted = highlighted 67 .replace(/(<\/?)(\w+)([^&]*?)(>)/g, '$1<span class="apb-tag">$2</span><span class="apb-attribute">$3</span>$4') 68 .replace(/(<!--[\s\S]*?-->)/g, '<span class="apb-comment">$1</span>'); 69 } 70 71 return highlighted; 72 } 73 74 function initCodeBlockCopyFeature() { 75 $(document).on('click', '.apb-copy-button', function(e) { 76 e.preventDefault(); 77 var button = $(this); 78 var codeBlock = button.closest('.wp-block-achang-pencil-box-code-box'); 79 var codeElement = codeBlock.find('code'); 80 var codeText = ''; 81 82 if (codeElement.length > 0) { 83 // ç²ååå§æåå §å®¹ï¼å¿½ç¥HTMLæ¨ç±¤ 84 var tempDiv = $('<div>').html(codeElement.html()); 85 tempDiv.find('span').each(function() { 86 $(this).replaceWith($(this).text()); 87 }); 88 codeText = tempDiv.text(); 89 } 90 91 if (!codeText) { 92 // åç¨æ¹æ¡ï¼ç´æ¥å¾ pre å ç´ ç²å 93 var preElement = codeBlock.find('pre'); 94 codeText = preElement.length > 0 ? preElement.text() : ''; 95 } 96 97 copyToClipboard(codeText, button); 98 }); 99 } 100 101 function copyToClipboard(text, button) { 102 // åªå 使ç¨ç¾ä»£ Clipboard APIï¼ä½éè¦å®å ¨æ¢ä»¶ 103 if (navigator.clipboard && navigator.clipboard.writeText && 104 (window.isSecureContext || location.protocol === 'https:' || location.hostname === 'localhost')) { 105 navigator.clipboard.writeText(text).then(function() { 106 showCopySuccess(button); 107 }).catch(function(err) { 108 console.log('Clipboard API failed, using fallback:', err); 109 fallbackCopyToClipboard(text, button); 110 }); 111 } else { 112 // ä½¿ç¨æ´å¼·å¥çåéæ¹æ¡ 113 fallbackCopyToClipboard(text, button); 114 } 115 } 116 117 function fallbackCopyToClipboard(text, button) { 118 // 檢測æ¯å¦çºææ©æå¹³æ¿è¨å 119 var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || 120 'ontouchstart' in window || navigator.maxTouchPoints > 0; 121 122 if (isMobile) { 123 // ææ©è¨å使ç¨ä¸åççç¥ 124 mobileCopyToClipboard(text, button); 125 } else { 126 // æ¡é¢è¨å使ç¨å³çµ±æ¹æ³ 127 desktopCopyToClipboard(text, button); 128 } 129 } 130 131 function desktopCopyToClipboard(text, button) { 132 var textArea = document.createElement('textarea'); 133 textArea.value = text; 134 textArea.style.position = 'fixed'; 135 textArea.style.left = '-999999px'; 136 textArea.style.top = '-999999px'; 137 textArea.style.opacity = '0'; 138 textArea.style.pointerEvents = 'none'; 139 document.body.appendChild(textArea); 140 try { 141 textArea.focus(); 142 textArea.select(); 143 textArea.setSelectionRange(0, text.length); 144 var successful = document.execCommand('copy'); 145 if (successful) { 146 showCopySuccess(button); 147 } else { 148 showCopyError(button); 149 } 150 } catch (err) { 151 console.log('Desktop copy failed:', err); 152 showCopyError(button); 153 } finally { 154 document.body.removeChild(textArea); 155 } 156 } 157 158 function mobileCopyToClipboard(text, button) { 159 // æ´å¥½çç§»å¨ç«¯å¤å¶çç¥ï¼ä½¿ç¨ç°ä»£APIå¹¶æä¾åéæ¹æ¡ 160 if (navigator.clipboard && navigator.clipboard.writeText) { 161 // ç°ä»£æµè§å¨æ¯æ Clipboard API 162 navigator.clipboard.writeText(text).then(function() { 163 showCopySuccess(button); 164 }).catch(function(err) { 165 console.log('Modern clipboard API failed on mobile:', err); 166 // 妿ç°ä»£API失败ï¼ä½¿ç¨ä¼ ç»æ¹æ³ 167 legacyMobileCopy(text, button); 168 }); 169 } else { 170 // 使ç¨ä¼ ç»æ¹æ³ 171 legacyMobileCopy(text, button); 172 } 173 } 174 175 function legacyMobileCopy(text, button) { 176 // 为移å¨ç«¯ä¼åçä¼ ç»å¤å¶æ¹æ³ 177 var textArea = document.createElement("textarea"); 178 textArea.value = text; 179 180 // è®¾ç½®æ ·å¼ä»¥ç¡®ä¿å¨ç§»å¨ç«¯æ£ç¡®å·¥ä½ 181 textArea.style.position = "fixed"; 182 textArea.style.top = "50%"; 183 textArea.style.left = "50%"; 184 textArea.style.transform = "translate(-50%, -50%)"; 185 textArea.style.width = "1px"; 186 textArea.style.height = "1px"; 187 textArea.style.padding = "0"; 188 textArea.style.border = "none"; 189 textArea.style.outline = "none"; 190 textArea.style.boxShadow = "none"; 191 textArea.style.background = "transparent";
192 textArea.style.fontSize = "12px"; 193 textArea.style.opacity = "0"; 194 textArea.style.zIndex = "9999"; 195 196 document.body.appendChild(textArea); 197 198 // 鿩并å¤å¶ææ¬ 199 textArea.focus(); 200 textArea.select(); 201 202 try { 203 var successful = document.execCommand('copy'); 204 if (successful) { 205 showCopySuccess(button); 206 } else { 207 showCopyError(button); 208 } 209 } catch (err) { 210 console.log('Legacy copy failed on mobile:', err); 211 // æåçåéæ¹æ¡ï¼æ¾ç¤ºæç¤º 212 fallbackMobileCopy(text, button); 213 } 214 215 // æ¸ ç 216 document.body.removeChild(textArea); 217 } 218 219 function fallbackMobileCopy(text, button) { 220 // å®å ¨çåéæ¹æ¡ï¼æ¾ç¤ºææ¬è®©ç¨æ·æå¨å¤å¶ 221 var modal = document.createElement('div'); 222 modal.style.cssText = ` 223 position: fixed; 224 top: 0; 225 left: 0; 226 width: 100%; 227 height: 100%; 228 background: rgba(0,0,0,0.7); 229 display: flex; 230 align-items: center; 231 justify-content: center; 232 z-index: 10000; 233 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 234 `; 235 236 var content = document.createElement('div'); 237 content.style.cssText = ` 238 background: #fff; 239 border-radius: 8px; 240 padding: 20px; 241 margin: 20px; 242 max-width: 90%; 243 max-height: 90%; 244 overflow: auto; 245 box-shadow: 0 4px 20px rgba(0,0,0,0.3); 246 `; 247 248 var title = document.createElement('h3'); 249 title.textContent = 'è¤è£½ç¨å¼ç¢¼'; 250 title.style.cssText = ` 251 margin: 0 0 15px 0; 252 color: #333; 253 font-size: 18px; 254 `; 255 256 var instructions = document.createElement('p'); 257 instructions.innerHTML = 'è«é¸å以䏿å並è¤è£½ï¼<br>(é·ææå鏿ãè¤è£½ã)'; 258 instructions.style.cssText = ` 259 margin: 0 0 15px 0; 260 color: #666; 261 font-size: 14px; 262 line-height: 1.4; 263 `; 264 265 var textArea = document.createElement('textarea'); 266 textArea.value = text; 267 textArea.style.cssText = ` 268 width: 100%; 269 min-height: 150px; 270 padding: 12px; 271 border: 1px solid #ddd; 272 border-radius: 4px; 273 font-family: 'Consolas', 'Monaco', 'Courier New', monospace; 274 font-size: 13px; 275 line-height: 1.4; 276 resize: vertical; 277 margin-bottom: 15px; 278 background: #f8f9fa; 279 `; 280 281 var buttonContainer = document.createElement('div'); 282 buttonContainer.style.cssText = ` 283 display: flex; 284 gap: 10px; 285 justify-content: flex-end; 286 `; 287 288 var copyBtn = document.createElement('button'); 289 copyBtn.textContent = 'è¤è£½'; 290 copyBtn.style.cssText = ` 291 padding: 8px 16px; 292 background: #007cba; 293 color: white; 294 border: none; 295 border-radius: 4px; 296 cursor: pointer; 297 font-size: 14px; 298 `; 299 300 var closeBtn = document.createElement('button'); 301 closeBtn.textContent = 'éé'; 302 closeBtn.style.cssText = ` 303 padding: 8px 16px; 304 background: #f0f0f0; 305 color: #333; 306 border: 1px solid #ddd; 307 border-radius: 4px; 308 cursor: pointer; 309 font-size: 14px; 310 `; 311 312 copyBtn.addEventListener('click', function() { 313 textArea.select(); 314 try { 315 var successful = document.execCommand('copy'); 316 if (successful) { 317 copyBtn.textContent = 'å·²è¤è£½!'; 318 copyBtn.style.background = '#28a745'; 319 setTimeout(function() { 320 copyBtn.textContent = 'è¤è£½'; 321 copyBtn.style.background = '#007cba'; 322 }, 2000); 323 } else { 324 copyBtn.textContent = '失æ'; 325 copyBtn.style.background = '#dc3545'; 326 setTimeout(function() { 327 copyBtn.textContent = 'è¤è£½'; 328 copyBtn.style.background = '#007cba'; 329 }, 1500); 330 } 331 } catch (err) { 332 console.log('Copy button failed:', err); 333 } 334 }); 335 336 closeBtn.addEventListener('click', function() { 337 document.body.removeChild(modal); 338 showCopySuccess(button); 339 }); 340 341 modal.addEventListener('click', function(e) { 342 if (e.target === modal) { 343 document.body.removeChild(modal); 344 showCopySuccess(button); 345 } 346 }); 347 348 buttonContainer.appendChild(copyBtn); 349 buttonContainer.appendChild(closeBtn); 350 351 content.appendChild(title);
352 content.appendChild(instructions); 353 content.appendChild(textArea); 354 content.appendChild(buttonContainer); 355 356 modal.appendChild(content); 357 document.body.appendChild(modal); 358 359 // èªå¨éä¸ææ¬ 360 setTimeout(function() { 361 textArea.focus(); 362 textArea.select(); 363 }, 100); 364 } 365 366 function showCopySuccess(button) { 367 var originalHtml = button.html(); 368 button.addClass('apb-copy-success').text('å·²è¤è£½!').prop('disabled', true); 369 setTimeout(function() { 370 button.removeClass('apb-copy-success').html(originalHtml).prop('disabled', false); 371 }, 2000); 372 } 373 374 function showCopyError(button) { 375 var originalHtml = button.html(); 376 button.addClass('apb-copy-error').text('失æ').prop('disabled', true); 377 setTimeout(function() { 378 button.removeClass('apb-copy-error').html(originalHtml).prop('disabled', false); 379 }, 1500); 380 } 381 382 function enhanceLineNumbers() { 383 $(".wp-block-achang-pencil-box-code-box").each(function() { 384 var codeBlock = $(this); 385 var lineNumbers = codeBlock.find('.apb-line-numbers'); 386 var codeContent = codeBlock.find('.apb-code-box-content'); 387 var codeElement = codeContent.find('code'); 388 389 if (lineNumbers.length > 0 && codeElement.length > 0) { 390 var codeText = codeElement.text(); 391 392 if (!codeText) { 393 lineNumbers.html('<div class="apb-line-number">1</div>'); 394 return; 395 } 396 397 // æ£ç¢ºè¨ç®è¡æ¸ï¼èæ ®æææè¡æ æ³ 398 var lines = codeText.split('\n'); 399 var lineCount = lines.length; 400 401 // åªæç¶æå¾ä¸è¡å®å ¨çºç©ºä¸ä¸æ¯å¯ä¸è¡æææ¸å°è¨æ¸ 402 if (lineCount > 1 && lines[lineCount - 1] === '') { 403 lineCount--; 404 } 405 406 var lineNumbersHtml = ''; 407 for (var i = 1; i <= Math.max(1, lineCount); i++) { 408 lineNumbersHtml += '<div class="apb-line-number">' + i + '</div>'; 409 } 410 lineNumbers.html(lineNumbersHtml); 411 412 // æ¹å滾å忥 413 var isSyncing = false; 414 var syncTimeout; 415 416 codeContent.off('scroll.apbSync').on('scroll.apbSync', function() { 417 if (isSyncing) return; 418 isSyncing = true; 419 420 var scrollTop = $(this).scrollTop(); 421 lineNumbers.scrollTop(scrollTop); 422 423 // ä½¿ç¨ requestAnimationFrame 確ä¿å¹³æ»åæ¥ 424 if (syncTimeout) clearTimeout(syncTimeout); 425 syncTimeout = setTimeout(function() { 426 isSyncing = false; 427 }, 16); // ç´ 60fps 428 }); 429 430 // 確ä¿è¡èåå䏿ç¨ç«æ»¾å 431 lineNumbers.off('scroll.apbPrevent').on('scroll.apbPrevent', function(e) { 432 if (!isSyncing) { 433 $(this).scrollTop(codeContent.scrollTop()); 434 } 435 }); 436 } 437 }); 438 } 439 440 function initAll() { 441 initCodeHighlighting(); 442 initCodeBlockCopyFeature(); 443 enhanceLineNumbers(); 444 } 445 446 initAll(); 447 448 var observer = new MutationObserver(function(mutations) { 449 mutations.forEach(function(mutation) { 450 if (mutation.addedNodes && mutation.addedNodes.length > 0) { 451 $(mutation.addedNodes).each(function() { 452 var node = $(this); 453 if (node.is('.wp-block-achang-pencil-box-code-box') || node.find('.wp-block-achang-pencil-box-code-box').length > 0) { 454 initAll(); 455 } 456 }); 457 } 458 }); 459 }); 460 461 observer.observe(document.body, { 462 childList: true, 463 subtree: true 464 }); 465 }); 466})( jQuery );
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.