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