1/** 2 * PyCode plugin: it embeds a Python script hosted in a remote repository. 3 * 4 * script.js: it defines the PyCode Wizard. 5 * 6 * @author Torpedo <dgtorpedo@gmail.com> 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @package script 9 */ 10 11var pycode_wiz = { 12 $wiz: null, 13 timer: null, 14 textArea: null, 15 16 /** 17 * Initialize the pycode_wiz by creating the needed HTML 18 * and attaching the eventhandlers. 19 */ 20 init: function($editor){ 21 // position relative to the text area 22 var pos = $editor.position(); 23 24 // create HTML Structure 25 pycode_wiz.$wiz = jQuery(document.createElement("div")) 26 .dialog({ 27 autoOpen: false, 28 draggable: true, 29 title: LANG.plugins.pycode.wizard, 30 resizable: false 31 }) 32 .html( 33 '<fieldset class="index">' + 34 '<legend>'+LANG.plugins.pycode.repository+'</legend>' + 35 '<div class="pycode__repo-src-url">' + 36 '<button id="pycode__b" type="button">' + 37 '<img src="'+DOKU_BASE+'lib/plugins/pycode/images/b.png"></img>' + 38 '</button>' + 39 '<button id="pycode__g" type="button">' + 40 '<img src="'+DOKU_BASE+'lib/plugins/pycode/images/g.png"></img>' + 41 '</button>' + 42 '<input id="pycode__src-url" type="text" disabled>' + 43 '</div>' + 44 '</fieldset>' + 45 46 '<fieldset class="options">' + 47 '<legend>'+LANG.plugins.pycode.options+'</legend>' + 48 '<div>' + 49 '<strong>'+LANG.plugins.pycode.embed+'</strong><br />' + 50 51 '<div class="pycode__embed-lns" id="pycode__left">' + 52 '<label><input id="pycode__opt-lns" type="checkbox">' + 53 LANG.plugins.pycode.lns+'</label>' + 54 '</div>' + 55 '<div class="pycode__embed-lns" id="pycode__right">' + 56 '<input id="pycode__lns-from" type="text" disabled>' + 57 ' : ' + 58 '<input id="pycode__lns-to" type="text" disabled>' + 59 '</div>' + 60 61 '<div class="pycode__embed-def" id="pycode__left">' + 62 '<label><input id="pycode__opt-def" type="checkbox">' + 63 LANG.plugins.pycode.def+'</label>' + 64 '</div>' + 65 '<div class="pycode__embed-def" id="pycode__right">' + 66 '<input id="pycode__def" type="text" disabled>' + 67 '</div>' + 68 69 '<div class="pycode__embed-cls" id="pycode__left">' + 70 '<label><input id="pycode__opt-cls" type="checkbox">' + 71 LANG.plugins.pycode.cls+'</label>' + 72 '</div>' + 73 '<div class="pycode__embed-cls" id="pycode__right">' + 74 '<input id="pycode__cls" type="text" disabled>' + 75 '</div>' + 76 '</div>' + 77 78 '<div>' + 79 '<strong>'+LANG.plugins.pycode.nums+'</strong><br />' + 80 81 '<div class="pycode__code-nums" id="pycode__left">' + 82 '<label><input id="pycode__opt-nums" type="checkbox">' + 83 LANG.plugins.pycode.change+'</label>' + 84 '</div>' + 85 '<div class="pycode__code-nums" id="pycode__right">' + 86 '<label><input type="radio" name="radio-nums" value="show" disabled>' + 87 LANG.plugins.pycode.show+'</label>' + 88 '<label><input type="radio" name="radio-nums" value="hide" disabled>' + 89 LANG.plugins.pycode.hide+'</label>' + 90 '</div>' + 91 '</div>' + 92 93 '<div>' + 94 '<strong>'+LANG.plugins.pycode.title+'</strong><br />' + 95 96 '<div class="pycode__code-title" id="pycode__left">' + 97 '<label><input id="pycode__opt-title" type="checkbox">' + 98 LANG.plugins.pycode.change+'</label>' + 99 '</div>' + 100 '<div class="pycode__code-title" id="pycode__right">' + 101 '<input id="pycode__title" type="text" disabled>' + 102 '</div>' + 103 '</div>' + 104 105 '<div>' + 106 '<strong>'+LANG.plugins.pycode.docstr+'</strong><br />' + 107 108 '<div class="pycode__code-docstr" id="pycode__left">' + 109 '<label><input id="pycode__opt-docstr" type="checkbox">' + 110 LANG.plugins.pycode.change+'</label>' + 111 '</div>' + 112 '<div class="pycode__code-docstr" id="pycode__right">' + 113 '<label><input type="radio" name="radio-docstr" value="show" disabled>' + 114 LANG.plugins.pycode.show+'</label>' + 115 '<label><input type="radio" name="radio-docstr" value="hide" disabled>' + 116 LANG.plugins.pycode.hide+'</label>' + 117 '</div>' + 118 '</div>' + 119 '</fieldset>' + 120 '<input type="submit" value="'+LANG.plugins.pycode.insert+'" id="pycode__insert">' 121 ) 122 .parent() 123 .attr("id","pycode__wiz") 124 .css({ 125 "position": "absolute", 126 "top": (pos.top+20)+"px", 127 "left": (pos.left+80)+"px" 128 }) 129 .hide() 130 .appendTo(".dokuwiki:first"); 131 132 pycode_wiz.textArea = $editor[0]; 133 134 // start to attach event handler 135 136 // the following is the table of all possibiles combinations, 137 // depending on flag, file extension and options 138 // 139 // | .py || .* | 140 // --------------------||-------------------- 141 // | | l | f |f+c| c || | l | f |f+c| c | 142 // ----------------------------||-------------------- 143 // nums | V | V | V | V | X || V | V | X | X | X | 144 // ----------------------------||-------------------- 145 // title | V | V | V | V | X || V | V | X | X | X | 146 // ----------------------------||-------------------- 147 // docstr | X | X | X | X | V || X | X | X | X | X | 148 // ----------------------------||-------------------- 149 150 // handle buttons for the repository 151 jQuery("#pycode__b").click(function() { 152 pycode_wiz.reset(".pycode__repo-src-url"); 153 jQuery("#pycode__b").fadeTo(0, 1); 154 jQuery("#pycode__g").fadeTo(0, 0.5); 155 if (jQuery("#pycode__src-url").prop("disabled") == true) { 156 jQuery("#pycode__src-url").prop("disabled", false); 157 } 158 jQuery("#pycode__src-url") 159 .val("https://bitbucket.org/<user>/<repo>/src/<branch>/<file>") 160 .click(function() {pycode_wiz.reset(".pycode__repo-src-url");}); 161 }); 162 jQuery("#pycode__g").click(function() { 163 pycode_wiz.reset(".pycode__repo-src-url"); 164 jQuery("#pycode__g").fadeTo(0, 1); 165 jQuery("#pycode__b").fadeTo(0, 0.5); 166 if (jQuery('#pycode__src-url').prop("disabled") == true) { 167 jQuery('#pycode__src-url').prop("disabled", false); 168 } 169 jQuery("#pycode__src-url") 170 .val("https://github.com/<user>/<repo>/blob/<branch>/<file>") 171 .click(function() {pycode_wiz.reset(".pycode__repo-src-url");}); 172 }); 173 174 // handle checkbox for embed code between two line numbers 175 jQuery("#pycode__opt-lns").change(function() { 176 if (jQuery("#pycode__opt-lns").prop("checked") == true) { 177 jQuery(".pycode__embed-lns input:text").prop("disabled", false); 178 pycode_wiz.disable(".pycode__embed-def"); 179 pycode_wiz.disable(".pycode__embed-cls"); 180 pycode_wiz.disable(".pycode__code-docstr"); 181 pycode_wiz.reset(".pycode__embed-def"); 182 pycode_wiz.reset(".pycode__embed-cls"); 183 pycode_wiz.reset(".pycode__code-docstr"); 184 } 185 else { 186 pycode_wiz.disable(".pycode__embed-lns"); 187 } 188 }); 189 190 // handle checkbox for embed code from function name 191 jQuery("#pycode__opt-def").change(function() { 192 if (jQuery("#pycode__opt-def").prop("checked") == true) { 193 jQuery("#pycode__def") 194 .prop("disabled", false) 195 .click(function() {pycode_wiz.reset(".pycode__embed-def");}); 196 pycode_wiz.disable(".pycode__embed-lns"); 197 pycode_wiz.disable(".pycode__code-docstr"); 198 pycode_wiz.reset(".pycode__code-docstr"); 199 } 200 else { 201 pycode_wiz.disable(".pycode__embed-def"); 202 pycode_wiz.reset(".pycode__embed-def"); 203 if (jQuery("#pycode__opt-cls").prop("checked") == true) { 204 pycode_wiz.disable(".pycode__code-nums"); 205 pycode_wiz.disable(".pycode__code-title"); 206 pycode_wiz.reset(".pycode__code-nums"); 207 } 208 } 209 }); 210 211 // handle checkbox for embed code from class name 212 jQuery("#pycode__opt-cls").change(function() { 213 if (jQuery("#pycode__opt-cls").prop("checked") == true) { 214 jQuery("#pycode__cls") 215 .prop("disabled", false) 216 .click(function() {pycode_wiz.reset(".pycode__embed-cls");}); 217 pycode_wiz.disable(".pycode__embed-lns"); 218 if (jQuery("#pycode__opt-def").prop("checked") == false) { 219 pycode_wiz.disable(".pycode__code-nums"); 220 pycode_wiz.disable(".pycode__code-title"); 221 pycode_wiz.reset(".pycode__code-nums"); 222 } 223 } 224 else { 225 pycode_wiz.disable(".pycode__embed-cls"); 226 pycode_wiz.disable(".pycode__code-docstr"); 227 pycode_wiz.reset(".pycode__embed-cls"); 228 pycode_wiz.reset(".pycode__code-docstr"); 229 } 230 }); 231 232 // handle checkbox for show/hide line numbers 233 jQuery("#pycode__opt-nums").change(function() { 234 if (jQuery("#pycode__opt-nums").prop("checked") == true) { 235 jQuery(".pycode__code-nums input:radio") 236 .prop("disabled", false) 237 .click(function() {pycode_wiz.reset('.pycode__code-nums');}); 238 if (jQuery("#pycode__opt-def").prop("checked") == false && 239 jQuery("#pycode__opt-cls").prop("checked") == true) { 240 pycode_wiz.disable(".pycode__embed-cls"); 241 pycode_wiz.disable(".pycode__code-docstr"); 242 pycode_wiz.reset(".pycode__embed-cls"); 243 pycode_wiz.reset(".pycode__code-docstr"); 244 } 245 } 246 else { 247 pycode_wiz.disable(".pycode__code-nums"); 248 pycode_wiz.reset(".pycode__code-nums"); 249 } 250 }); 251 252 // handle checkbox for define new title for the code 253 jQuery("#pycode__opt-title").change(function() { 254 if (jQuery("#pycode__opt-title").prop("checked") == true) { 255 jQuery("#pycode__title").prop("disabled", false); 256 if (jQuery("#pycode__opt-def").prop("checked") == false && 257 jQuery("#pycode__opt-cls").prop("checked") == true) { 258 pycode_wiz.disable(".pycode__embed-cls"); 259 pycode_wiz.disable(".pycode__code-docstr"); 260 pycode_wiz.reset(".pycode__embed-cls"); 261 pycode_wiz.reset(".pycode__code-docstr"); 262 } 263 264 } 265 else { 266 pycode_wiz.disable(".pycode__code-title"); 267 } 268 }); 269 270 // handle checkbox for show/hide docstring 271 jQuery("#pycode__opt-docstr").change(function() { 272 if (jQuery("#pycode__opt-docstr").prop("checked") == true) { 273 jQuery(".pycode__code-docstr input:radio") 274 .prop("disabled", false) 275 .click(function() {pycode_wiz.reset('.pycode__code-docstr');}); 276 pycode_wiz.disable(".pycode__embed-lns"); 277 pycode_wiz.disable(".pycode__embed-def"); 278 pycode_wiz.disable(".pycode__code-nums"); 279 pycode_wiz.disable(".pycode__code-title"); 280 pycode_wiz.reset(".pycode__embed-def"); 281 pycode_wiz.reset(".pycode__code-nums"); 282 } 283 else { 284 pycode_wiz.disable(".pycode__code-docstr"); 285 pycode_wiz.reset(".pycode__code-docstr"); 286 } 287 }); 288 289 // handle button for insert the syntax 290 jQuery("#pycode__insert").click(pycode_wiz.insertPycode); 291 292 // handle button for close the wizard 293 jQuery("#pycode__wiz").find(".ui-dialog-titlebar-close").click(pycode_wiz.hide); 294 }, 295 296 /** 297 * Disable input objects belong to a given div. 298 * 299 * @param (obj) obj class name of a div 300 */ 301 disable: function(obj) { 302 jQuery(obj+" input:checkbox").prop("checked", false); 303 jQuery(obj+" input:radio").prop("disabled", true); 304 jQuery(obj+" input:text").prop("disabled", true); 305 }, 306 307 /** 308 * Set css rules defined for required fields missing. 309 * 310 * @param (obj) obj class name of a div 311 */ 312 require: function(obj) { 313 jQuery(obj+" input:radio").css("outline", "2px solid #FCC"); 314 jQuery(obj+" input:text").css("background-color", "#FCC"); 315 }, 316 317 /** 318 * Reset css rules previously defined for required fields missing. 319 * 320 * @param (obj) obj class name of a div 321 */ 322 reset: function(obj) { 323 jQuery(obj+" input:radio").css("outline", ""); 324 jQuery(obj+" input:text").css("background-color", ""); 325 }, 326 327 /** 328 * Get the extension of a given src-url. 329 * 330 * @param (str) src_url the url to the source code 331 */ 332 getExtension: function(src_url) { 333 var ext = src_url.slice(-3); // get .py 334 if (ext == ".py") { 335 return "py"; 336 } 337 else { 338 return "no-py"; 339 } 340 }, 341 342 /** 343 * Insert the syntax into the textarea, 344 * replacing the current selection or at the cursor position. 345 */ 346 insertPycode: function() { 347 var data = { 348 "src_url": null, 349 "flag": null, 350 "name": null, 351 "nums": null, 352 "title": null, 353 "docstr": null 354 }; 355 var error = new Array; 356 357 // get the values from the fields 358 // and check if some data has been missed 359 360 // get value from src-url field 361 if (jQuery("#pycode__src-url").val() == "") { 362 error.push("no-src-url"); 363 } 364 else { 365 data["src_url"] = jQuery("#pycode__src-url").val(); 366 if (pycode_wiz.getExtension(data["src_url"]) == "no-py" && 367 (jQuery("#pycode__opt-def").prop("checked") == true || 368 jQuery("#pycode__opt-cls").prop("checked") == true)) { 369 error.push("no-py"); 370 } 371 } 372 373 // get value from name lines field 374 if (jQuery("#pycode__opt-lns").prop("checked") == true) { 375 data["flag"] = "l"; 376 data["name"] = jQuery("#pycode__lns-from").val()+":"+jQuery("#pycode__lns-to").val(); 377 } 378 // get value from name function field 379 else if ((jQuery("#pycode__opt-def").prop("checked") == true) && 380 (jQuery("#pycode__opt-cls").prop("checked") == false)) { 381 data["flag"] = "f"; 382 if (jQuery("#pycode__def").val() == "") { 383 error.push("no-def"); 384 } 385 else { 386 data["name"] = jQuery("#pycode__def").val(); 387 } 388 } 389 // get value from names method and class fields 390 else if ((jQuery("#pycode__opt-def").prop("checked") == true) && 391 (jQuery("#pycode__opt-cls").prop("checked") == true)) { 392 data["flag"] = "f"; 393 if (jQuery("#pycode__def").val() == "" && 394 jQuery("#pycode__cls").val() == "") { 395 error.push("no-def-cls"); 396 } 397 else if (jQuery("#pycode__def").val() != "" && 398 jQuery("#pycode__cls").val() == "") { 399 error.push("no-cls"); 400 } 401 else if (jQuery("#pycode__def").val() == "" && 402 jQuery("#pycode__cls").val() != "") { 403 error.push("no-def"); 404 } 405 else { 406 data["name"] = jQuery("#pycode__def").val()+" "+jQuery("#pycode__cls").val(); 407 } 408 } 409 // get value from name class field 410 else if ((jQuery("#pycode__opt-def").prop("checked") == false) && 411 (jQuery("#pycode__opt-cls").prop("checked") == true)) { 412 data["flag"] = "c"; 413 if (jQuery("#pycode__cls").val() != "") { 414 data["name"] = jQuery("#pycode__cls").val(); 415 } 416 else { 417 error.push("no-cls"); 418 } 419 } 420 // embed the whole file 421 else { 422 data["flag"] = ""; 423 } 424 425 426 // get value from line numbers option 427 if (jQuery("#pycode__opt-nums").prop("checked") == true) { 428 if (jQuery(".pycode__code-nums input:radio:checked").val() == "show") { 429 data["nums"] = "-nums = 1"; 430 } 431 else if (jQuery(".pycode__code-nums input:radio:checked").val() == "hide") { 432 data["nums"] = "-nums = 0"; 433 } 434 else { 435 error.push("no-nums"); 436 } 437 } 438 439 // get value from title option 440 if (jQuery("#pycode__opt-title").prop("checked") == true) { 441 title = jQuery("#pycode__title").val(); 442 data["title"] = '-title = "'+title+'"'; 443 } 444 445 // get value from docstring option 446 if (jQuery("#pycode__opt-docstr").prop("checked") == true && 447 jQuery("#pycode__opt-cls").prop("checked") == true) { 448 if (jQuery(".pycode__code-docstr input:radio:checked").val() == "show") { 449 data["docstr"] = "-docstr = 1"; 450 } 451 else if (jQuery(".pycode__code-docstr input:radio:checked").val() == "hide") { 452 data["docstr"] = "-docstr = 0"; 453 } 454 else { 455 error.push("no-docstr"); 456 } 457 } 458 else if (jQuery("#pycode__opt-docstr").prop("checked") == true && 459 jQuery("#pycode__opt-cls").prop("checked") == false) { 460 error.push("no-cls"); 461 } 462 463 if (error.length == 0) { 464 // depending on the choices made, print the right syntax 465 var syntax = "<pycode"; 466 for (var k in data) { 467 if (data[k] != null) { 468 if (data[k] == "") { 469 syntax += data[k]; 470 } 471 else { 472 syntax += " " + data[k]; 473 } 474 } 475 } 476 syntax += ">"; 477 // get current selection/cursor position in a given textArea 478 // with DWgetSelection() defined in lib/scripts/textselection.js 479 sel = DWgetSelection(pycode_wiz.textArea); 480 // insert/replace given text at the current cursor position 481 // with pasteText() defined in lib/scripts/textselection.js 482 pasteText(sel, syntax, 0); 483 // finally close the wizard 484 pycode_wiz.hide(); 485 } 486 else { 487 // highlight missing fields 488 error.forEach(function(item, index, array) { 489 if (item == "no-src-url") { 490 pycode_wiz.require(".pycode__repo-src-url"); 491 } 492 else if (item == "no-py") { 493 pycode_wiz.disable(".pycode__embed-def"); 494 pycode_wiz.disable(".pycode__embed-cls"); 495 pycode_wiz.reset(".pycode__embed-def"); 496 pycode_wiz.reset(".pycode__embed-cls"); 497 } 498 else if (item == "no-def") { 499 pycode_wiz.require(".pycode__embed-def"); 500 } 501 else if (item == "no-def-cls") { 502 pycode_wiz.require(".pycode__embed-def"); 503 pycode_wiz.require(".pycode__embed-cls"); 504 } 505 else if (item == "no-cls") { 506 pycode_wiz.require(".pycode__embed-cls"); 507 } 508 else if (item == "no-nums") { 509 pycode_wiz.require(".pycode__code-nums"); 510 } 511 else if (item == "no-docstr") { 512 pycode_wiz.require(".pycode__code-docstr"); 513 } 514 }) 515 } 516 }, 517 518 /** 519 * Show the pycode wizard 520 */ 521 show: function() { 522 pycode_wiz.selection = DWgetSelection(pycode_wiz.textArea); 523 pycode_wiz.$wiz.show(); 524 }, 525 526 /** 527 * Hide the pycode wizard 528 */ 529 hide: function() { 530 pycode_wiz.$wiz.hide(); 531 pycode_wiz.textArea.focus(); 532 }, 533 534 /** 535 * Toggle the pycode wizard 536 */ 537 toggle: function() { 538 if (pycode_wiz.$wiz.css("display") == "none") { 539 pycode_wiz.show(); 540 } 541 else { 542 pycode_wiz.hide(); 543 } 544 } 545}; 546 547/** 548 * It adds button action for the toolbar button 549 * 550 * @param (obj) $btn jQuery button element to add the action to. 551 * @param (arr) props Associative array of button properties. 552 * @param (str) edid ID of the editor textarea. 553 * @return (str) If button should be appended, return the id for in 554 * aria-controls, otherwise an empty string. 555 */ 556function addBtnActionPyCode($btn, props, edid) { 557 pycode_wiz.init(jQuery('#' + edid)); 558 $btn.click(function () { 559 pycode_wiz.toggle(); 560 return false; 561 }); 562 return true; 563} 564