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').click(dw_linkwiz.hide); 61 dw_linkwiz.$entry.keyup(dw_linkwiz.onEntry); 62 jQuery(dw_linkwiz.result).delegate('a', 'click', 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(stxt) { 244 //link += '|'+stxt; 245 link = dw_linkwiz.val.open+stxt+' | '+link+dw_linkwiz.val.close; 246 so = stxt.length-2; 247 eo = stxt.length+2; 248 } 249 else { 250 link = dw_linkwiz.val.open+link+dw_linkwiz.val.close; 251 so = link.length-4; 252 eo = 2; 253 } 254 255 } 256 257 pasteText(sel,link,{startofs: so, endofs: eo}); 258 dw_linkwiz.hide(); 259 260 // reset the entry to the parent namespace 261 dw_linkwiz.$entry.val(dw_linkwiz.$entry.val().replace(/[^:]*$/, '')); 262 }, 263 264 /** 265 * Start the page/namespace lookup timer 266 * 267 * Calls autocomplete_exec when the timer runs out 268 */ 269 autocomplete: function(){ 270 if(dw_linkwiz.timer !== null){ 271 window.clearTimeout(dw_linkwiz.timer); 272 dw_linkwiz.timer = null; 273 } 274 275 dw_linkwiz.timer = window.setTimeout(dw_linkwiz.autocomplete_exec,350); 276 }, 277 278 /** 279 * Executes the AJAX call for the page/namespace lookup 280 */ 281 autocomplete_exec: function(){ 282 var $res = jQuery(dw_linkwiz.result); 283 dw_linkwiz.deselect(); 284 $res.html('<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />') 285 .load( 286 DOKU_BASE + 'lib/exe/ajax.php', 287 { 288 call: 'linkwiz', 289 q: dw_linkwiz.$entry.val() 290 } 291 ); 292 }, 293 294 /** 295 * Show the link wizard 296 */ 297 show: function(){ 298 dw_linkwiz.selection = DWgetSelection(dw_linkwiz.textArea); 299 dw_linkwiz.$wiz.show(); 300 dw_linkwiz.$entry.focus(); 301 dw_linkwiz.autocomplete(); 302 }, 303 304 /** 305 * Hide the link wizard 306 */ 307 hide: function(){ 308 dw_linkwiz.$wiz.hide(); 309 dw_linkwiz.textArea.focus(); 310 }, 311 312 /** 313 * Toggle the link wizard 314 */ 315 toggle: function(){ 316 if(dw_linkwiz.$wiz.css('display') == 'none'){ 317 dw_linkwiz.show(); 318 }else{ 319 dw_linkwiz.hide(); 320 } 321 } 322}; 323