1/* DOKUWIKI:include scripts/tagselector.js */ 2 3jQuery(function(){ 4 // TODO: make this configurable by the admin 5 var currentInterval = 1000; // Starting interval in milliseconds 6 var maxInterval = 10000; // Maximum interval is 10 seconds 7 8 const BuildmanagerStates = { 9 STATE_NON_EXISTENT: 1, 10 STATE_RUNNING: 2, 11 STATE_SCHEDULED: 3, 12 STATE_FINISHED: 4, 13 STATE_ERROR: 5, 14 }; 15 16 var isLoadingSnippet = false; 17 18 /** 19 * Scan the document for doxycode markers that represent dynamically loaded code snippets. 20 * 21 * The doxycode_markers contain custom data fields that represent the cache files. 22 * We extract all markers so the state of the associated doxygen builds can be obtained in a single request. 23 * 24 * When the code snippets are successfully loaded the markers are removed later. If no more markers 25 * are present we return an empty array which indicates that dynamic loading is finished for this page. 26 * 27 * @returns {Array} contains the xml and html hash names that represent the doxycode cache files 28 * @author Lukas Probsthain <lukas.probsthain@gmail.com> 29 */ 30 function scanAndPrepareData() { 31 var dataToSend = []; 32 33 jQuery('.doxycode_marker').each(function() { 34 var xmlHash = jQuery(this).data('doxycode-xml-hash'); 35 var htmlHash = jQuery(this).data('doxycode-html-hash'); 36 if (xmlHash || htmlHash) { 37 dataToSend.push({xmlHash: xmlHash, htmlHash: htmlHash}); 38 } 39 }); 40 return dataToSend; 41 } 42 43 /** 44 * Handles the state response for the dynamically loaded code snippets. 45 * 46 * This is called from requestJobStatus. 47 * The function will place an appropriate state message obtained from the 48 * global LANG variable inside the doxycode_marker container. 49 * 50 * If a successful build was reported for a dynamically loaded code snippet 51 * the function will request the parsed code snippet HTML from the server via AJAX. 52 * 53 * @param {Array} response Each entry contains the xml and html hash from the request with the reported state 54 * @author Lukas Probsthain <lukas.probsthain@gmail.com> 55 */ 56 function handleStatusResponse(response) { 57 response.forEach(function(hashInfo) { 58 $markers = jQuery('.doxycode_marker').filter(function() { 59 return jQuery(this).data('doxycode-xml-hash') === hashInfo.xmlHash && 60 jQuery(this).data('doxycode-html-hash') === hashInfo.htmlHash; 61 }); 62 63 var $loadingAnimation; 64 if(parseInt(hashInfo.state) != BuildmanagerStates.STATE_FINISHED) { 65 $loadingAnimation = jQuery('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />'); 66 } 67 68 $markers.each(function() { 69 var $currentMarker = jQuery(this); 70 $currentMarker.empty(); 71 72 var message; 73 switch(parseInt(hashInfo.state)) { 74 case BuildmanagerStates.STATE_NON_EXISTENT: 75 message = LANG.plugins.doxycode.msg_not_existent; 76 break; 77 case BuildmanagerStates.STATE_SCHEDULED: 78 message = LANG.plugins.doxycode.msg_scheduled; 79 break; 80 case BuildmanagerStates.STATE_RUNNING: 81 message = LANG.plugins.doxycode.msg_running; 82 break; 83 case BuildmanagerStates.STATE_ERROR: 84 message = LANG.plugins.doxycode.msg_error; 85 break; 86 case BuildmanagerStates.STATE_FINISHED: 87 loadSnippet({ 88 xmlHash: hashInfo.xmlHash, 89 htmlHash: hashInfo.htmlHash 90 }); 91 return; // Skip appending for finished state 92 } 93 94 if ($loadingAnimation) { 95 $currentMarker.append($loadingAnimation.clone()); 96 } 97 98 if (message) { 99 $currentMarker.append(message); 100 } 101 }); 102 }); 103 } 104 105 /** 106 * Handles the insertion of dynamically loaded code snippet HTML into the code container. 107 * 108 * @param {Array} response Contains the xml and html hashes along with the parsed code snippet HTML 109 * @author Lukas Probsthain <lukas.probsthain@gmail.com> 110 */ 111 function loadSnippetHtml(response) { 112 113 $markers = jQuery('.doxycode_marker').filter(function() { 114 return jQuery(this).data('doxycode-xml-hash') === response.hashes.xmlHash && 115 jQuery(this).data('doxycode-html-hash') === response.hashes.htmlHash; 116 }); 117 118 $markers.each(function() { 119 // dynamically load the HTML for this snippet! 120 var parent_element = jQuery(this).parent(); 121 jQuery(this).remove(); 122 jQuery(parent_element).append(response.html); 123 }); 124 } 125 126 /** 127 * Function to request the build status of dynamically loaded code snippets via AJAX. 128 * 129 * It obtains the xml and html hashes (which represent the cache files) of the code snippets with scanAndPrepareData and sends a request 130 * for all dynamically loaded code snippets to plugin_doxycode_check_status. 131 * 132 * If dynamically loaded code snippets are present in the page it will call itself again. 133 * The time period after which the request is repeated increases with each request to reduce load on the server. 134 * 135 * @author Lukas Probsthain <lukas.probsthain@gmail.com> 136 */ 137 function requestJobStatus() { 138 var data = scanAndPrepareData(); 139 if (data.length === 0) { 140 return; 141 } 142 143 jQuery.post( 144 DOKU_BASE + 'lib/exe/ajax.php', 145 { 146 call: 'plugin_doxycode_check_status', 147 hashes: data 148 }, 149 function(response) { 150 handleStatusResponse(response); 151 currentInterval = Math.min(currentInterval + 100, maxInterval); 152 setTimeout(requestJobStatus, currentInterval); 153 }, 154 'json' 155 ).fail(function(jqXHR, textStatus, errorThrown) { 156 console.error("AJAX error:", textStatus, errorThrown); 157 currentInterval = Math.min(currentInterval + 1000, maxInterval); 158 setTimeout(requestJobStatus, currentInterval); 159 }); 160 } 161 162 /** 163 * Request the parsed code snippet HTML from the server via AJAX. 164 * 165 * @param {Array} data Contains the xml and html hashes for the code snippet cache files 166 * @author Lukas Probsthain <lukas.probsthain@gmail.com> 167 */ 168 function loadSnippet(data) { 169 if (isLoadingSnippet) { 170 return; 171 } 172 173 isLoadingSnippet = true; 174 175 jQuery.post( 176 DOKU_BASE + 'lib/exe/ajax.php', 177 { 178 call: 'plugin_doxycode_get_snippet_html', 179 hashes: data 180 }, 181 function(response) { 182 isLoadingSnippet = false; 183 loadSnippetHtml(response); 184 }, 185 'json' 186 ).fail(function(jqXHR, textStatus, errorThrown) { 187 console.error("AJAX error:", textStatus, errorThrown); 188 isLoadingSnippet = false; 189 }); 190 } 191 192 requestJobStatus(); 193}); 194 195/** 196 * Add button action for the doxycode tag selector button 197 * 198 * Adapted from the linkwiz dialog by Andreas Gohr (see {@link https://github.com/dokuwiki/dokuwiki/blob/8985cadc85d51290e4908456c2afc923fd0f0332/lib/scripts/toolbar.js#L221-L230}). 199 * 200 * @param DOMElement btn Button element to add the action to 201 * @param array props Associative array of button properties 202 * @param string edid ID of the editor textarea 203 * @return boolean If button should be appended 204 * @author Lukas Probsthain <lukas.probsthain@gmail.com> 205 */ 206function addBtnActionDoxycodeTagSelector($btn, props, edid) { 207 doxycode_tagselector.init(jQuery('#'+edid)); 208 jQuery($btn).click(function(e){ 209 doxycode_tagselector.val = props; 210 doxycode_tagselector.toggle(); 211 e.preventDefault(); 212 return ''; 213 }); 214 return 'doxycode__tagselector'; 215}