1/** 2 * The Link Wizard 3 * 4 * @author Andreas Gohr <gohr@cosmocode.de> 5 * @author Pierre Spring <pierre.spring@caillou.ch> 6 */ 7var dw_linkwiz = { 8 $wiz: null, 9 $entry: null, 10 result: null, 11 timer: null, 12 textArea: null, 13 selected: null, 14 selection: null, 15 16 /** 17 * Initialize the dw_linkwizard 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 if(dw_linkwiz.$wiz) 26 return; 27 dw_linkwiz.$wiz = jQuery(document.createElement('div')) 28 .dialog({ 29 autoOpen: false, 30 draggable: true, 31 title: LANG.linkwiz, 32 resizable: false 33 }) 34 .html( 35 '<div>'+LANG.linkto+' <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ 36 '<div id="link__wiz_result"></div>' 37 ) 38 .parent() 39 .attr('id','link__wiz') 40 .css({ 41 'position': 'absolute', 42 'top': (pos.top+20)+'px', 43 'left': (pos.left+80)+'px' 44 }) 45 .hide() 46 .appendTo('.dokuwiki:first'); 47 48 dw_linkwiz.textArea = $editor[0]; 49 dw_linkwiz.result = jQuery('#link__wiz_result')[0]; 50 51 // scrollview correction on arrow up/down gets easier 52 jQuery(dw_linkwiz.result).css('position', 'relative'); 53 54 dw_linkwiz.$entry = jQuery('#link__wiz_entry'); 55 if(JSINFO.namespace){ 56 dw_linkwiz.$entry.val(JSINFO.namespace+':'); 57 } 58 59 // attach event handlers 60 jQuery('#link__wiz .ui-dialog-titlebar-close').on('click', dw_linkwiz.hide); 61 dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry); 62 jQuery(dw_linkwiz.result).on('click', 'a', dw_linkwiz.onResultClick); 63 }, 64 65 /** 66 * handle all keyup events in the entry field 67 */ 68 onEntry: function(e){ 69 if(e.keyCode == 37 || e.keyCode == 39){ //left/right 70 return true; //ignore 71 } 72 if(e.keyCode == 27){ //Escape 73 dw_linkwiz.hide(); 74 e.preventDefault(); 75 e.stopPropagation(); 76 return false; 77 } 78 if(e.keyCode == 38){ //Up 79 dw_linkwiz.select(dw_linkwiz.selected -1); 80 e.preventDefault(); 81 e.stopPropagation(); 82 return false; 83 } 84 if(e.keyCode == 40){ //Down 85 dw_linkwiz.select(dw_linkwiz.selected +1); 86 e.preventDefault(); 87 e.stopPropagation(); 88 return false; 89 } 90 if(e.keyCode == 13){ //Enter 91 if(dw_linkwiz.selected > -1){ 92 var $obj = dw_linkwiz.$getResult(dw_linkwiz.selected); 93 if($obj.length > 0){ 94 dw_linkwiz.resultClick($obj.find('a')[0]); 95 } 96 }else if(dw_linkwiz.$entry.val()){ 97 dw_linkwiz.insertLink(dw_linkwiz.$entry.val()); 98 } 99 100 e.preventDefault(); 101 e.stopPropagation(); 102 return false; 103 } 104 dw_linkwiz.autocomplete(); 105 }, 106 107 /** 108 * Get one of the results by index 109 * 110 * @param num int result div to return 111 * @returns DOMObject or null 112 */ 113 getResult: function(num){ 114 DEPRECATED('use dw_linkwiz.$getResult()[0] instead'); 115 return dw_linkwiz.$getResult()[0] || null; 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 return jQuery(dw_linkwiz.result).find('div').eq(num); 126 }, 127 128 /** 129 * Select the given result 130 */ 131 select: function(num){ 132 if(num < 0){ 133 dw_linkwiz.deselect(); 134 return; 135 } 136 137 var $obj = dw_linkwiz.$getResult(num); 138 if ($obj.length === 0) { 139 return; 140 } 141 142 dw_linkwiz.deselect(); 143 $obj.addClass('selected'); 144 145 // make sure the item is viewable in the scroll view 146 147 //getting child position within the parent 148 var childPos = $obj.position().top; 149 //getting difference between the childs top and parents viewable area 150 var yDiff = childPos + $obj.outerHeight() - jQuery(dw_linkwiz.result).innerHeight(); 151 152 if (childPos < 0) { 153 //if childPos is above viewable area (that's why it goes negative) 154 jQuery(dw_linkwiz.result)[0].scrollTop += childPos; 155 } else if(yDiff > 0) { 156 // if difference between childs top and parents viewable area is 157 // greater than the height of a childDiv 158 jQuery(dw_linkwiz.result)[0].scrollTop += yDiff; 159 } 160 161 dw_linkwiz.selected = num; 162 }, 163 164 /** 165 * deselect a result if any is selected 166 */ 167 deselect: function(){ 168 if(dw_linkwiz.selected > -1){ 169 dw_linkwiz.$getResult(dw_linkwiz.selected).removeClass('selected'); 170 } 171 dw_linkwiz.selected = -1; 172 }, 173 174 /** 175 * Handle clicks in the result set an dispatch them to 176 * resultClick() 177 */ 178 onResultClick: function(e){ 179 if(!jQuery(this).is('a')) { 180 return; 181 } 182 e.stopPropagation(); 183 e.preventDefault(); 184 dw_linkwiz.resultClick(this); 185 return false; 186 }, 187 188 /** 189 * Handles the "click" on a given result anchor 190 */ 191 resultClick: function(a){ 192 dw_linkwiz.$entry.val(a.title); 193 if(a.title == '' || a.title.substr(a.title.length-1) == ':'){ 194 dw_linkwiz.autocomplete_exec(); 195 }else{ 196 if (jQuery(a.nextSibling).is('span')) { 197 dw_linkwiz.insertLink(a.nextSibling.innerHTML); 198 }else{ 199 dw_linkwiz.insertLink(''); 200 } 201 } 202 }, 203 204 /** 205 * Insert the id currently in the entry box to the textarea, 206 * replacing the current selection or at the cursor position. 207 * When no selection is available the given title will be used 208 * as link title instead 209 */ 210 insertLink: function(title){ 211 var link = dw_linkwiz.$entry.val(), 212 sel, stxt; 213 if(!link) { 214 return; 215 } 216 217 sel = DWgetSelection(dw_linkwiz.textArea); 218 if(sel.start == 0 && sel.end == 0) { 219 sel = dw_linkwiz.selection; 220 } 221 222 stxt = sel.getText(); 223 224 // don't include trailing space in selection 225 if(stxt.charAt(stxt.length - 1) == ' '){ 226 sel.end--; 227 stxt = sel.getText(); 228 } 229 230 if(!stxt && !DOKU_UHC) { 231 stxt=title; 232 } 233 234 // prepend colon inside namespaces for non namespace pages 235 if(dw_linkwiz.textArea.form.id.value.indexOf(':') != -1 && 236 link.indexOf(':') == -1){ 237 link = ':' + link; 238 } 239 240 var so = link.length; 241 var eo = 0; 242 if(dw_linkwiz.val){ 243 if(dw_linkwiz.val.open) { 244 so += dw_linkwiz.val.open.length; 245 link = dw_linkwiz.val.open+link; 246 } 247 link += '|'; 248 so += 1; 249 if(stxt) { 250 link += stxt; 251 } 252 if(dw_linkwiz.val.close) { 253 link += dw_linkwiz.val.close; 254 eo = dw_linkwiz.val.close.length; 255 } 256 } 257 258 pasteText(sel,link,{startofs: so, endofs: eo}); 259 dw_linkwiz.hide(); 260 261 // reset the entry to the parent namespace 262 var externallinkpattern = new RegExp('^((f|ht)tps?:)?//', 'i'), 263 entry_value; 264 if (externallinkpattern.test(dw_linkwiz.$entry.val())) { 265 if (JSINFO.namespace) { 266 entry_value = JSINFO.namespace + ':'; 267 } else { 268 entry_value = ''; //reset whole external links 269 } 270 } else { 271 entry_value = dw_linkwiz.$entry.val().replace(/[^:]*$/, '') 272 } 273 dw_linkwiz.$entry.val(entry_value); 274 }, 275 276 /** 277 * Start the page/namespace lookup timer 278 * 279 * Calls autocomplete_exec when the timer runs out 280 */ 281 autocomplete: function(){ 282 if(dw_linkwiz.timer !== null){ 283 window.clearTimeout(dw_linkwiz.timer); 284 dw_linkwiz.timer = null; 285 } 286 287 dw_linkwiz.timer = window.setTimeout(dw_linkwiz.autocomplete_exec,350); 288 }, 289 290 /** 291 * Executes the AJAX call for the page/namespace lookup 292 */ 293 autocomplete_exec: function(){ 294 var $res = jQuery(dw_linkwiz.result); 295 dw_linkwiz.deselect(); 296 $res.html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />') 297 .load( 298 DOKU_BASE + 'lib/exe/ajax.php', 299 { 300 call: 'linkwiz', 301 q: dw_linkwiz.$entry.val() 302 } 303 ); 304 }, 305 306 /** 307 * Show the link wizard 308 */ 309 show: function(){ 310 dw_linkwiz.selection = DWgetSelection(dw_linkwiz.textArea); 311 dw_linkwiz.$wiz.show(); 312 dw_linkwiz.$entry.focus(); 313 dw_linkwiz.autocomplete(); 314 315 // Move the cursor to the end of the input 316 var temp = dw_linkwiz.$entry.val(); 317 dw_linkwiz.$entry.val(''); 318 dw_linkwiz.$entry.val(temp); 319 }, 320 321 /** 322 * Hide the link wizard 323 */ 324 hide: function(){ 325 dw_linkwiz.$wiz.hide(); 326 dw_linkwiz.textArea.focus(); 327 }, 328 329 /** 330 * Toggle the link wizard 331 */ 332 toggle: function(){ 333 if(dw_linkwiz.$wiz.css('display') == 'none'){ 334 dw_linkwiz.show(); 335 }else{ 336 dw_linkwiz.hide(); 337 } 338 } 339}; 340