1/** 2 * The Namespace picker dialog 3 * 4 * Based on the code from "The Link Wizard"/linkwiz.js 5 * from Andreas Gohr <gohr@cosmocode.de> and Pierre Spring <pierre.spring@caillou.ch> 6 * 7 * @author LarsDW223 8 */ 9var bc_nspicker = { 10 $picker: null, 11 $entry: null, 12 result: null, 13 timer: null, 14 textArea: null, 15 selected: null, 16 selection: null, 17 18 /** 19 * Initialize the bc_nspicker by creating the needed HTML 20 * and attaching the eventhandlers 21 */ 22 init: function ($editor) { 23 "use strict"; 24 // position relative to the text area 25 var pos = $editor.position(); 26 27 // create HTML Structure 28 if (bc_nspicker.$picker) { 29 return; 30 } 31 bc_nspicker.$picker = jQuery(document.createElement('div')) 32 .dialog({ 33 autoOpen: false, 34 draggable: true, 35 title: LANG.plugins.bookcreator.namespace_picker, 36 resizable: false 37 }) 38 .html( 39 '<div>' + LANG.plugins.bookcreator.select_namespace + ' <input type="text" class="edit" id="bc__nspicker_entry" autocomplete="off" />' + 40 '<input type="button" value="' + LANG.plugins.bookcreator.select + '" id="bc__nspicker_select">' + 41 '<input type="button" value="' + LANG.plugins.bookcreator.cancel + '" id="bc__nspicker_cancel">' + 42 '<br><input type="checkbox" value="Recursive" id="bc__nspicker_recursive">' + LANG.plugins.bookcreator.add_subns_too + 43 '</div>' + 44 '<div id="bc__nspicker_result"></div>' 45 ) 46 .parent() 47 .attr('id', 'bc__nspicker') 48 .css({ 49 'position': 'absolute', 50 'top': (pos.top + 20) + 'px', //overwritten later with position of Add Namespace button. 51 'left': (pos.left + 80) + 'px' 52 }) 53 .hide() 54 .appendTo('.dokuwiki:first'); 55 56 bc_nspicker.textArea = $editor[0]; 57 bc_nspicker.result = jQuery('#bc__nspicker_result')[0]; 58 59 // scrollview correction on arrow up/down gets easier 60 jQuery(bc_nspicker.result).css('position', 'relative'); 61 62 bc_nspicker.$entry = jQuery('#bc__nspicker_entry'); 63 if (JSINFO.namespace) { 64 bc_nspicker.$entry.val(JSINFO.namespace + ':'); 65 } 66 67 // attach event handlers 68 jQuery('#bc__nspicker .ui-dialog-titlebar-close').on('click', bc_nspicker.hide); 69 jQuery('#bc__nspicker_select').on('click', bc_nspicker.selectNamespace_exec); 70 jQuery('#bc__nspicker_cancel').on('click', bc_nspicker.hide); 71 bc_nspicker.$entry.keyup(bc_nspicker.onEntry); 72 jQuery(bc_nspicker.result).on('click', 'a', bc_nspicker.onResultClick); 73 }, 74 75 /** 76 * handle all keyup events in the entry field 77 */ 78 onEntry: function (e) { 79 "use strict"; 80 if (e.keyCode === 37 || e.keyCode === 39) { //left/right 81 return true; //ignore 82 } 83 if (e.keyCode === 27) { //Escape 84 bc_nspicker.hide(); 85 e.preventDefault(); 86 e.stopPropagation(); 87 return false; 88 } 89 if (e.keyCode === 38) { //Up 90 bc_nspicker.select(bc_nspicker.selected - 1); 91 e.preventDefault(); 92 e.stopPropagation(); 93 return false; 94 } 95 if (e.keyCode === 40) { //Down 96 bc_nspicker.select(bc_nspicker.selected + 1); 97 e.preventDefault(); 98 e.stopPropagation(); 99 return false; 100 } 101 if (e.keyCode === 13) { //Enter 102 if (bc_nspicker.selected > -1) { 103 var $obj = bc_nspicker.$getResult(bc_nspicker.selected); 104 if ($obj.length > 0) { 105 bc_nspicker.resultClick($obj.find('a')[0]); 106 } 107 } else if (bc_nspicker.$entry.val()) { 108 bc_nspicker.selectNamespace_exec(); 109 } 110 111 e.preventDefault(); 112 e.stopPropagation(); 113 return false; 114 } 115 bc_nspicker.autocomplete(); 116 }, 117 118 /** 119 * Get one of the results by index 120 * 121 * @param num int result div to return 122 * @returns jQuery object 123 */ 124 $getResult: function (num) { 125 "use strict"; 126 return jQuery(bc_nspicker.result).find('div').eq(num); 127 }, 128 129 /** 130 * Select the given result 131 */ 132 select: function (num) { 133 "use strict"; 134 if (num < 0) { 135 bc_nspicker.deselect(); 136 return; 137 } 138 139 var $obj = bc_nspicker.$getResult(num); 140 if ($obj.length === 0) { 141 return; 142 } 143 144 bc_nspicker.deselect(); 145 $obj.addClass('selected'); 146 147 // make sure the item is viewable in the scroll view 148 149 //getting child position within the parent 150 var childPos = $obj.position().top; 151 //getting difference between the childs top and parents viewable area 152 var yDiff = childPos + $obj.outerHeight() - jQuery(bc_nspicker.result).innerHeight(); 153 154 if (childPos < 0) { 155 //if childPos is above viewable area (that's why it goes negative) 156 jQuery(bc_nspicker.result)[0].scrollTop += childPos; 157 } else if (yDiff > 0) { 158 // if difference between childs top and parents viewable area is 159 // greater than the height of a childDiv 160 jQuery(bc_nspicker.result)[0].scrollTop += yDiff; 161 } 162 163 bc_nspicker.selected = num; 164 }, 165 166 /** 167 * deselect a result if any is selected 168 */ 169 deselect: function () { 170 "use strict"; 171 if (bc_nspicker.selected > -1) { 172 bc_nspicker.$getResult(bc_nspicker.selected).removeClass('selected'); 173 } 174 bc_nspicker.selected = -1; 175 }, 176 177 /** 178 * Handle clicks in the result set an dispatch them to 179 * resultClick() 180 */ 181 onResultClick: function (e) { 182 "use strict"; 183 if (!jQuery(this).is('a')) { 184 return; 185 } 186 e.stopPropagation(); 187 e.preventDefault(); 188 bc_nspicker.resultClick(this); 189 return false; 190 }, 191 192 /** 193 * Handles the "click" on a given result anchor 194 */ 195 resultClick: function (a) { 196 "use strict"; 197 if (a.title === '' || a.title.substr(a.title.length - 1) === ':') { 198 bc_nspicker.$entry.val(a.title); 199 bc_nspicker.autocomplete_exec(); 200 } 201 }, 202 203 /** 204 * Start the page/namespace lookup timer 205 * 206 * Calls autocomplete_exec when the timer runs out 207 */ 208 autocomplete: function () { 209 "use strict"; 210 if (bc_nspicker.timer !== null) { 211 window.clearTimeout(bc_nspicker.timer); 212 bc_nspicker.timer = null; 213 } 214 215 bc_nspicker.timer = window.setTimeout(bc_nspicker.autocomplete_exec, 350); 216 }, 217 218 /** 219 * Executes the AJAX call for the page/namespace lookup 220 */ 221 autocomplete_exec: function () { 222 "use strict"; 223 var $res = jQuery(bc_nspicker.result); 224 bc_nspicker.deselect(); 225 $res.html('<img src="' + DOKU_BASE + 'lib/images/throbber.gif" alt="" width="16" height="16" />') 226 .load( 227 DOKU_BASE + 'lib/exe/ajax.php', 228 { 229 call: 'linkwiz', 230 q: bc_nspicker.$entry.val() 231 } 232 ); 233 }, 234 235 /** 236 * Show the link wizard 237 */ 238 show: function () { 239 "use strict"; 240 bc_nspicker.selection = DWgetSelection(bc_nspicker.textArea); 241 bc_nspicker.$picker.show(); 242 bc_nspicker.$entry.focus(); 243 bc_nspicker.autocomplete(); 244 245 // Move the cursor to the end of the input 246 var temp = bc_nspicker.$entry.val(); 247 bc_nspicker.$entry.val(''); 248 bc_nspicker.$entry.val(temp); 249 }, 250 251 /** 252 * Hide the link wizard 253 */ 254 hide: function () { 255 "use strict"; 256 bc_nspicker.$picker.hide(); 257 bc_nspicker.textArea.focus(); 258 }, 259 260 /** 261 * Toggle the link wizard 262 */ 263 toggle: function () { 264 "use strict"; 265 if (bc_nspicker.$picker.css('display') === 'none') { 266 bc_nspicker.show(); 267 } else { 268 bc_nspicker.hide(); 269 } 270 }, 271 272 /** 273 * Executes the AJAX call for the selected namespace lookup. 274 * Parameter "ns" is the namespace to search through. Parameter 275 * "r" specifies if the search should be recursive or not. 276 */ 277 selectNamespace_exec: function () { 278 "use strict"; 279 var $recursive = jQuery('#bc__nspicker_recursive'); 280 281 jQuery.post( 282 DOKU_BASE + 'lib/exe/ajax.php', 283 { 284 call: 'plugin_bookcreator_call', 285 action: 'searchPages', 286 ns: bc_nspicker.$entry.val(), 287 r: $recursive.is(':checked'), 288 sectok: jQuery('input[name="sectok"]').val() 289 }, 290 bc_nspicker.selectNamespace, 291 'json' 292 ); 293 }, 294 295 /** 296 * Select Namespace. 297 * Add all pages in the selected Namespace to the book, show 298 * window with added pages and then close/hide the Namespace 299 * picker. 300 */ 301 selectNamespace: function (data) { 302 "use strict"; 303 var content; 304 var pages; 305 var name; 306 307 // Go through the array of pages, add them and prepare 308 // a message for the user 309 pages = 0; 310 content = LANG.plugins.bookcreator.added_pages + "\n\n"; 311 if (data.hasOwnProperty('pages')) { 312 jQuery(data.pages).each(function (index) { 313 name = data.pages [index]; 314 Bookcreator.selectedpages.addPage (name); 315 content += name + "\n"; 316 pages += 1; 317 }); 318 } 319 if (pages === 0) { 320 content += LANG.plugins.bookcreator.no_pages_selected + "\n"; 321 } 322 323 BookManager.updateListsFromStorage(); 324 window.alert(content); 325 bc_nspicker.hide(); 326 } 327}; 328