1jQuery(function() { 2 // Check if user has edit permission 3 if (!JSINFO.codeblockedit_canedit) { 4 return; // Don't show edit buttons if user can't edit 5 } 6 7 // Check if on a page with content (not in edit mode) 8 if (document.querySelector('#dw__editform')) { 9 return; // Don't add edit buttons while in edit mode 10 } 11 12 // Function to handle edit click 13 var handleEdit = function(event) { 14 event.preventDefault(); 15 event.stopPropagation(); 16 17 var $btn = jQuery(this); 18 var index = $btn.data('index'); 19 var hid = 'codeblock_' + index; 20 21 // Redirect to standard DokuWiki editor with codeblockindex and hid parameters 22 // hid is used by DokuWiki to redirect back to this section after saving 23 var url = DOKU_BASE + 'doku.php?id=' + encodeURIComponent(JSINFO.id) + '&do=edit&codeblockindex=' + index + '&hid=' + hid; 24 window.location.href = url; 25 }; 26 27 let sup = 'desktop'; 28 if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { 29 sup = 'mobile'; 30 } 31 32 var blockIndex = 0; 33 34 // Process all code and file blocks - wrap the <pre> element directly like copy2clipboard does 35 document.querySelectorAll('pre.code, pre.file').forEach(function(preElem) { 36 // Check if already processed 37 if (preElem.dataset.codeblockeditProcessed) return; 38 preElem.dataset.codeblockeditProcessed = 'true'; 39 40 var currentIndex = blockIndex++; 41 42 // Create the edit button 43 var editBtn = document.createElement('button'); 44 editBtn.setAttribute('title', 'Edit this code block'); 45 editBtn.classList.add('codeblockedit-btn'); 46 editBtn.dataset.index = currentIndex; 47 editBtn.addEventListener('click', handleEdit); 48 49 // Check if already wrapped by copy2clipboard 50 var existingWrapper = preElem.parentNode; 51 var useExistingWrapper = existingWrapper && 52 existingWrapper.classList && 53 existingWrapper.classList.contains('cp2clipcont'); 54 55 var btnWrapper; 56 if (useExistingWrapper) { 57 // Reuse existing wrapper from copy2clipboard 58 btnWrapper = existingWrapper; 59 btnWrapper.classList.add('codeblockedit-wrapper', sup); 60 } else { 61 // Create our own wrapper around the <pre> element (same as copy2clipboard) 62 btnWrapper = document.createElement('div'); 63 btnWrapper.classList.add('codeblockedit-wrapper', sup); 64 65 // Wrap the pre element 66 preElem.parentNode.insertBefore(btnWrapper, preElem); 67 btnWrapper.appendChild(preElem); 68 69 // Transfer margin from pre to wrapper for proper alignment 70 var marginTop = window.getComputedStyle(preElem)['margin-top']; 71 if (marginTop !== '0px') { 72 btnWrapper.style['margin-top'] = marginTop; 73 preElem.style['margin-top'] = '0'; 74 } 75 var marginBottom = window.getComputedStyle(preElem)['margin-bottom']; 76 if (marginBottom !== '0px') { 77 btnWrapper.style['margin-bottom'] = marginBottom; 78 preElem.style['margin-bottom'] = '0'; 79 } 80 } 81 82 // Add anchor ID to wrapper for redirect back after edit 83 btnWrapper.id = 'codeblock_' + currentIndex; 84 85 btnWrapper.appendChild(editBtn); 86 }); 87 88 // After adding all IDs, check if we need to scroll to a codeblock anchor 89 // This handles the case where DokuWiki redirects with #codeblock_N after save 90 // but the ID didn't exist in the initial HTML (it's added by JavaScript) 91 if (window.location.hash && window.location.hash.match(/^#codeblock_\d+$/)) { 92 var targetId = window.location.hash.substring(1); 93 var targetElement = document.getElementById(targetId); 94 if (targetElement) { 95 // Use setTimeout to ensure the DOM is fully ready and other plugins have run 96 setTimeout(function() { 97 // Expand any collapsed sections (sectiontoggle plugin compatibility) 98 // Collect all hidden ancestors first, then expand from outermost to innermost 99 var hiddenAncestors = []; 100 var parent = targetElement.parentElement; 101 102 while (parent && parent !== document.body) { 103 // Check if this element is hidden (collapsed by sectiontoggle) 104 var computedDisplay = window.getComputedStyle(parent).display; 105 if (computedDisplay === 'none' || parent.style.display === 'none') { 106 hiddenAncestors.push(parent); 107 } 108 parent = parent.parentElement; 109 } 110 111 // Expand from outermost (last in array) to innermost (first in array) 112 // This ensures parent sections are expanded before child sections 113 for (var i = hiddenAncestors.length - 1; i >= 0; i--) { 114 var hiddenElem = hiddenAncestors[i]; 115 // Find the header that controls this section 116 // sectiontoggle hides the nextElementSibling of the header 117 var header = hiddenElem.previousElementSibling; 118 if (header && /^H[1-6]$/.test(header.tagName) && header.classList.contains('st_closed')) { 119 // Expand this section by toggling classes 120 header.classList.remove('st_closed'); 121 header.classList.add('st_opened'); 122 hiddenElem.style.display = ''; 123 } else { 124 // Fallback: just show the element if we can't find the controlling header 125 hiddenElem.style.display = ''; 126 } 127 } 128 129 // Now scroll to the target 130 targetElement.scrollIntoView({ behavior: 'auto', block: 'start' }); 131 }, 100); // Slightly longer delay to ensure sectiontoggle has finished 132 } 133 } 134}); 135