1/** 2 * The Link Wizard 3 * 4 * @author Andreas Gohr <gohr@cosmocode.de> 5 */ 6linkwiz = { 7 wiz: null, 8 entry: null, 9 result: null, 10 timer: null, 11 sack: null, 12 textArea: null, 13 selected: -1, 14 15 /** 16 * Initialize the linkwizard by creating the needed HTML 17 * and attaching the eventhandlers 18 */ 19 init: function(textArea){ 20 // prepare AJAX object 21 linkwiz.sack = new sack(DOKU_BASE + 'lib/exe/ajax.php'); 22 linkwiz.sack.AjaxFailedAlert = ''; 23 linkwiz.sack.encodeURIString = false; 24 25 // create HTML Structure 26 linkwiz.wiz = document.createElement('div'); 27 linkwiz.wiz.id = 'link__wiz'; 28 linkwiz.wiz.className = 'picker'; 29 linkwiz.wiz.style.top = (findPosY(textArea)+20)+'px'; 30 linkwiz.wiz.style.left = (findPosX(textArea)+80)+'px'; 31 linkwiz.wiz.style.display = 'none'; 32 33 linkwiz.wiz.innerHTML = 34 '<div id="link__wiz_header">'+ 35 '<img src="'+DOKU_BASE+'lib/images/close.png" width="16" height="16" align="right" alt="" id="link__wiz_close" />'+ 36 'Link Wizard</div>'+ 37 '<div>Link: <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ 38 '<div id="link__wiz_result"></div>'; 39 textArea.form.parentNode.appendChild(linkwiz.wiz); 40 linkwiz.textArea = textArea; 41 linkwiz.result = $('link__wiz_result'); 42 linkwiz.entry = $('link__wiz_entry'); 43 44 // attach event handlers 45 var obj; 46 obj = $('link__wiz_close'); 47 obj.onclick = linkwiz.hide; 48 49 linkwiz.sack.elementObj = linkwiz.result; 50 addEvent(linkwiz.entry,'keyup',linkwiz.onEntry); 51 addEvent(linkwiz.result,'click',linkwiz.onResultClick); 52 drag.attach(linkwiz.wiz,$('link__wiz_header')); 53 }, 54 55 /** 56 * handle all keyup events in the entry field 57 */ 58 onEntry: function(e){ 59 if(e.keyCode == 37 || e.keyCode == 39){ //left/right 60 return true; //ignore 61 } 62 if(e.keyCode == 38){ //Up 63 linkwiz.select(linkwiz.selected -1); 64 e.preventDefault(); 65 e.stopPropagation(); 66 return false; 67 } 68 if(e.keyCode == 40){ //Down 69 linkwiz.select(linkwiz.selected +1); 70 e.preventDefault(); 71 e.stopPropagation(); 72 return false; 73 } 74 if(e.keyCode == 13){ //Enter 75 if(linkwiz.selected > -1){ 76 var obj = linkwiz.getResult(linkwiz.selected); 77 if(obj){ 78 var a = obj.getElementsByTagName('A')[0]; 79 linkwiz.resultClick(a); 80 } 81 }else if(linkwiz.entry.value){ 82 linkwiz.insertLink(linkwiz.entry.value); 83 } 84 85 e.preventDefault(); 86 e.stopPropagation(); 87 return false; 88 } 89 linkwiz.autocomplete(); 90 }, 91 92 /** 93 * Get one of the result by index 94 * 95 * @param int result div to return 96 * @returns DOMObject or null 97 */ 98 getResult: function(num){ 99 var obj; 100 var childs = linkwiz.result.getElementsByTagName('DIV'); 101 obj = childs[num]; 102 if(obj){ 103 return obj; 104 }else{ 105 return null; 106 } 107 }, 108 109 /** 110 * Select the given result 111 */ 112 select: function(num){ 113 if(num < 0){ 114 linkwiz.deselect(); 115 return; 116 } 117 118 var obj = linkwiz.getResult(num); 119 if(obj){ 120 linkwiz.deselect(); 121 obj.className += ' selected'; 122 123 // make sure the item is viewable in the scroll view 124 // FIXME check IE compatibility 125 if(obj.offsetTop > linkwiz.result.scrollTop + linkwiz.result.clientHeight){ 126 linkwiz.result.scrollTop += obj.clientHeight; 127 }else if(obj.offsetTop - linkwiz.result.clientHeight < linkwiz.result.scrollTop){ // this works but isn't quite right, fixes welcome 128 linkwiz.result.scrollTop -= obj.clientHeight; 129 } 130 // now recheck - if still not in view, the user used the mouse to scroll 131 if( (obj.offsetTop > linkwiz.result.scrollTop + linkwiz.result.clientHeight) || 132 (obj.offsetTop < linkwiz.result.scrollTop) ){ 133 obj.scrollIntoView(); 134 } 135 136 linkwiz.selected = num; 137 } 138 }, 139 140 /** 141 * deselect a result if any is selected 142 */ 143 deselect: function(){ 144 if(linkwiz.selected > -1){ 145 var obj = linkwiz.getResult(linkwiz.selected); 146 if(obj){ 147 obj.className = obj.className.replace(/ ?selected/,''); 148 } 149 } 150 linkwiz.selected = -1; 151 }, 152 153 /** 154 * Handle clicks in the result set an dispatch them to 155 * resultClick() 156 */ 157 onResultClick: function(e){ 158 if(e.target.tagName != 'A') return; 159 e.stopPropagation(); 160 e.preventDefault(); 161 linkwiz.resultClick(e.target); 162 return false; 163 }, 164 165 /** 166 * Handles the "click" on a given result anchor 167 */ 168 resultClick: function(a){ 169 var id = a.title; 170 if(id == '' || id.substr(id.length-1) == ':'){ 171 linkwiz.entry.value = id; 172 linkwiz.autocomplete_exec(); 173 }else{ 174 linkwiz.entry.value = id; 175 if(a.nextSibling && a.nextSibling.tagName == 'SPAN'){ 176 linkwiz.insertLink(a.nextSibling.innerHTML); 177 }else{ 178 linkwiz.insertLink(''); 179 } 180 } 181 }, 182 183 /** 184 * Insert the id currently in the entry box to the textarea, 185 * replacing the current selection or at the curso postion. 186 * When no selection is available the given title will be used 187 * as link title instead 188 */ 189 insertLink: function(title){ 190 if(!linkwiz.entry.value) return; 191 var sel = getSelection(linkwiz.textArea); 192 var stxt = sel.getText(); 193 if(!stxt) stxt=title; 194 195 var link = '[['+linkwiz.entry.value; 196 if(stxt) link += '|'+stxt; 197 link += ']]'; 198 199 var so = linkwiz.entry.value.length+3; 200 var eo = 2; 201 202 pasteText(sel,link,{startofs: so, endofs: eo}); 203 linkwiz.hide(); 204 }, 205 206 /** 207 * Start the page/namespace lookup timer 208 * 209 * Calls autocomplete_exec when the timer runs out 210 */ 211 autocomplete: function(){ 212 if(linkwiz.timer !== null){ 213 window.clearTimeout(linkwiz.timer); 214 linkwiz.timer = null; 215 } 216 217 linkwiz.timer = window.setTimeout(linkwiz.autocomplete_exec,350); 218 }, 219 220 /** 221 * Executes the AJAX call for the page/namespace lookup 222 */ 223 autocomplete_exec: function(){ 224 linkwiz.deselect(); 225 linkwiz.result.innerHTML = '<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />'; 226 linkwiz.sack.runAJAX('call=linkwiz&q='+encodeURI(linkwiz.entry.value)); 227 }, 228 229 /** 230 * Clears the result area 231 */ 232 clear: function(){ 233 linkwiz.result.innerHTML = 'Search for a matching page name above, or browse through the pages on the right'; 234 linkwiz.entry.value = ''; 235 }, 236 237 /** 238 * Show the linkwizard 239 */ 240 show: function(){ 241 linkwiz.wiz.style['display'] = ''; 242 linkwiz.entry.focus(); 243 linkwiz.autocomplete(); 244 }, 245 246 /** 247 * Hide the link wizard 248 */ 249 hide: function(){ 250 linkwiz.wiz.style['display'] = 'none'; 251 }, 252 253 /** 254 * Toggle the link wizard 255 */ 256 toggle: function(){ 257 if(linkwiz.wiz.style['display'] == 'none'){ 258 linkwiz.show(); 259 }else{ 260 linkwiz.hide(); 261 } 262 }, 263}; 264 265