1/** 2 * EditSections2 Plugin for DokuWiki / script.js 3 * 4 * Replaces section edit highlighting events 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Kazutaka Miyasaka <kazmiya@gmail.com> 8 */ 9 10(function() { 11 /** 12 * Lookup table for section edit id (startPos => secedit_id) 13 */ 14 var editIdLookup = {}; 15 16 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 17 18 // compatibility check 19 if ( 20 typeof DEPRECATED === 'function' || 21 typeof addInitEvent === 'undefined' 22 ) { 23 // for DokuWiki Angua or later 24 jQuery(replaceSectionEditButtonEvents); 25 } else if (typeof JSINFO === 'object') { 26 if (JSINFO.plugin_editsections2) { 27 // for DokuWiki Anteater and Rincewind 28 addInitEvent(replaceSectionEditButtonEvents_Anteater); 29 } else { 30 // for DokuWiki Lemming 31 addInitEvent(replaceSectionEditButtonEvents_Lemming); 32 } 33 } 34 35 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 36 37 /** 38 * Replaces mouseover events on section edit buttons 39 */ 40 function replaceSectionEditButtonEvents() { 41 jQuery('form.btn_secedit') 42 .each(function() { 43 addEditIdLookupTable(this); 44 }) 45 .unbind('mouseover') 46 .bind('mouseover', function(event) { 47 highlightSections(event); 48 }) 49 // FIXME: a huge change has happened... will make a real fix later 50 // https://github.com/splitbrain/dokuwiki/commit/870c8a4b77dd7c2cfdc14045f8604b5bbf34c01e 51 .unbind('mouseout') 52 .bind('mouseout', function(event) { 53 jQuery('.section_highlight').removeClass('section_highlight'); 54 }); 55 } 56 57 /** 58 * Returns start/end value of the section edit range 59 */ 60 function getRangeValue(range, startOrEnd) { 61 var matched, 62 ret; 63 64 if (!range || !(matched = /^(\d+)-(\d*)$/.exec(range.value))) { 65 ret = false; 66 } else if (startOrEnd === 'start') { 67 ret = Number(matched[1]); 68 } else if (matched[2].length) { 69 ret = Number(matched[2]); 70 } else { 71 ret = 'last'; 72 } 73 74 return ret; 75 } 76 77 /** 78 * Scans and adds section edit id lookup table 79 */ 80 function addEditIdLookupTable(sectionEditForm) { 81 var parent, 82 idMatched, 83 startPos; 84 85 parent = sectionEditForm.parentNode; 86 87 if ( 88 parent && 89 parent.tagName && 90 parent.tagName.toLowerCase() === 'div' && 91 parent.className && 92 (idMatched = /\b(?:editbutton_(\d+))\b/.exec(parent.className)) && 93 (startPos = getRangeValue(sectionEditForm.range, 'start')) 94 ) { 95 editIdLookup[startPos] = idMatched[1]; 96 } 97 } 98 99 /** 100 * Checks if an element is heading 101 */ 102 function isHeading(element) { 103 return element.tagName && /^H[1-6]/i.test(element.tagName); 104 } 105 106 /** 107 * Highlights sections in the edit range 108 */ 109 function highlightSections(event) { 110 var sectionEditForm, 111 endPos, 112 stopClassRegExp, 113 doNotHighlightHeadings, 114 cursor; 115 116 sectionEditForm = event.target.form; 117 118 if (!sectionEditForm) { 119 return; 120 } 121 122 endPos = getRangeValue(sectionEditForm.range, 'end'); 123 124 // set stopClass regexp 125 if (endPos === false) { 126 return; 127 } else if (endPos === 'last') { 128 stopClassRegExp = /\b(?:footnotes)\b/; 129 } else if (editIdLookup[endPos + 1]) { 130 stopClassRegExp = new RegExp( 131 '\\b(?:footnotes|sectionedit' + 132 String(editIdLookup[endPos + 1]).replace(/(\W)/g, '\\$1') + 133 ')\\b' 134 ); 135 } else { 136 // edittable plugin etc. 137 return; 138 } 139 140 doNotHighlightHeadings = 141 JSINFO.plugin_editsections2.highlight_target === 'exclude_headings'; 142 143 cursor = sectionEditForm.parentNode; 144 145 // highlight until the stopClass appeared 146 while (cursor = cursor.nextSibling) { 147 if (!cursor.className) { 148 continue; 149 } 150 151 if (stopClassRegExp.test(cursor.className)) { 152 break; 153 } 154 155 if ( 156 !(doNotHighlightHeadings && isHeading(cursor)) && 157 !/\b(?:editbutton_section)\b/.test(cursor.className) 158 ) { 159 cursor.className += ' section_highlight'; 160 } 161 } 162 } 163 164 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 165 166 /** 167 * Replaces mouseover events on section edit buttons 168 * (for DokuWiki Anteater and Rincewind) 169 */ 170 function replaceSectionEditButtonEvents_Anteater() { 171 var i, 172 iMax, 173 parent, 174 events, 175 guid, 176 buttonForms, 177 sectionEditForms = []; 178 179 buttonForms = getElementsByClass('btn_secedit', document, 'form'); 180 181 // extract section edit forms 182 for (i = 0, iMax = buttonForms.length; i < iMax; i++) { 183 parent = buttonForms[i].parentNode; 184 185 // parent element must be 'div.editbutton_section' 186 if ( 187 parent && 188 parent.tagName && 189 parent.tagName.toLowerCase() === 'div' && 190 parent.className && 191 /\b(?:editbutton_section)\b/.test(parent.className) 192 ) { 193 sectionEditForms[sectionEditForms.length] = buttonForms[i]; 194 } 195 } 196 197 // remove events and collect section info 198 for (i = 0, iMax = sectionEditForms.length; i < iMax; i++) { 199 events = sectionEditForms[i].events; 200 201 // remove all of the previously-set mouseover events from the button 202 if (events && events.mouseover) { 203 for (guid in events.mouseover) { 204 removeEvent( 205 sectionEditForms[i], 'mouseover', events.mouseover[guid] 206 ); 207 } 208 } 209 210 addEditIdLookupTable(sectionEditForms[i]); 211 } 212 213 // add new event to highlight sections to be edited 214 for (i = 0, iMax = sectionEditForms.length; i < iMax; i++) { 215 addEvent( 216 sectionEditForms[i], 217 'mouseover', 218 highlightSections 219 ); 220 } 221 } 222 223 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 224 225 /** 226 * Replaces mouseover events on section edit buttons 227 * (for DokuWiki Lemming) 228 */ 229 function replaceSectionEditButtonEvents_Lemming() { 230 var i, 231 iMax, 232 events, 233 guid, 234 buttonForms; 235 236 buttonForms = getElementsByClass('btn_secedit', document, 'form'); 237 238 for (i = 0, iMax = buttonForms.length; i < iMax; i++) { 239 events = buttonForms[i].events; 240 241 // remove all of the previously-set mouseover events from the button 242 if (events && events.mouseover) { 243 for (guid in events.mouseover) { 244 removeEvent( 245 buttonForms[i], 'mouseover', events.mouseover[guid] 246 ); 247 } 248 } 249 250 // add new mouseover event to highlight sections to be edited 251 addEvent(buttonForms[i], 'mouseover', highlightSections_Lemming); 252 } 253 } 254 255 /** 256 * Highlights sections in the edit range 257 * (for DokuWiki Lemming or earlier) 258 */ 259 function highlightSections_Lemming(event) { 260 var buttonForm, 261 sectionEditForm, 262 cursor, 263 startPos, 264 endPos; 265 266 buttonForm = event.target.form; 267 268 // get the end position of the section 269 endPos = getRangeValue(buttonForm.lines, 'end'); 270 271 if (endPos === false) { 272 return; 273 } 274 275 cursor = buttonForm.parentNode; 276 277 if (!cursor.tagName || cursor.tagName.toLowerCase() !== 'div') { 278 return; 279 } 280 281 // add "section_highlight" class to DIV elements in the edit range 282 while (cursor = cursor.nextSibling) { 283 if ( 284 !cursor.tagName || 285 cursor.tagName.toLowerCase() !== 'div' || 286 !cursor.className 287 ) { 288 continue; 289 } 290 291 if ( 292 /\b(?:secedit)\b/.test(cursor.className) && 293 endPos !== 'last' && 294 (sectionEditForm = cursor.getElementsByTagName('form').item(0)) && 295 (startPos = getRangeValue(sectionEditForm.lines, 'start')) !== false && 296 endPos < startPos 297 ) { 298 // out of the edit range 299 break; 300 } 301 302 if (/\b(?:level\d)\b/.test(cursor.className)) { 303 cursor.className += ' section_highlight'; 304 } 305 } 306 } 307})(); 308