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