1/** 2 * Functions for text editing (toolbar stuff) 3 * 4 * @todo I'm no JS guru please help if you know how to improve 5 * @author Andreas Gohr <andi@splitbrain.org> 6 */ 7 8/** 9 * Creates a toolbar button through the DOM 10 * 11 * Style the buttons through the toolbutton class 12 * 13 * @author Andreas Gohr <andi@splitbrain.org> 14 */ 15function createToolButton(icon,label,key,id){ 16 var btn = document.createElement('button'); 17 var ico = document.createElement('img'); 18 19 // preapare the basic button stuff 20 btn.className = 'toolbutton'; 21 btn.title = label; 22 if(key){ 23 btn.title += ' [ALT+'+key.toUpperCase()+']'; 24 btn.accesskey = key; 25 } 26 27 // set IDs if given 28 if(id){ 29 btn.id = id; 30 ico.id = id+'_ico'; 31 } 32 33 // create the icon and add it to the button 34 ico.src = DOKU_BASE+'lib/images/toolbar/'+icon; 35 btn.appendChild(ico); 36 37 return btn; 38} 39 40/** 41 * Creates a picker window for inserting text 42 * 43 * The given list can be an associative array with text,icon pairs 44 * or a simple list of text. Style the picker window through the picker 45 * class or the picker buttons with the pickerbutton class. Picker 46 * windows are appended to the body and created invisible. 47 * 48 * @author Andreas Gohr <andi@splitbrain.org> 49 */ 50function createPicker(id,list,icobase,edid){ 51 var cnt = list.length; 52 53 var picker = document.createElement('div'); 54 picker.className = 'picker'; 55 picker.id = id; 56 picker.style.position = 'absolute'; 57 picker.style.display = 'none'; 58 59 for(var key in list){ 60 var btn = document.createElement('button'); 61 62 btn.className = 'pickerbutton' 63 64 // associative array? 65 if(isNaN(key)){ 66 var ico = document.createElement('img'); 67 ico.src = DOKU_BASE+'lib/images/'+icobase+'/'+list[key]; 68 btn.title = key; 69 btn.appendChild(ico); 70 eval("btn.onclick = function(){pickerInsert('"+id+"','"+ 71 jsEscape(key)+"','"+ 72 jsEscape(edid) 73 +"');return false;}"); 74 }else{ 75 var txt = document.createTextNode(list[key]); 76 btn.title = list[key]; 77 btn.appendChild(txt); 78 eval("btn.onclick = function(){pickerInsert('"+id+"','"+ 79 jsEscape(list[key])+"','"+ 80 jsEscape(edid) 81 +"');return false;}"); 82 } 83 84 picker.appendChild(btn); 85 } 86 var body = document.getElementsByTagName('body')[0]; 87 body.appendChild(picker); 88} 89 90/** 91 * Called by picker buttons to insert Text and close the picker again 92 * 93 * @author Andreas Gohr <andi@splitbrain.org> 94 */ 95function pickerInsert(pickerid,text,edid){ 96 // insert 97 insertAtCarret(edid,text); 98 // close picker 99 pobj = document.getElementById(pickerid); 100 pobj.style.display = 'none'; 101} 102 103/** 104 * Show a previosly created picker window 105 * 106 * @author Andreas Gohr <andi@splitbrain.org> 107 */ 108function showPicker(pickerid,btn){ 109 var picker = document.getElementById(pickerid); 110 var x = findPosX(btn); 111 var y = findPosY(btn); 112 if(picker.style.display == 'none'){ 113 picker.style.display = 'block'; 114 picker.style.left = (x+3)+'px'; 115 picker.style.top = (y+btn.offsetHeight+3)+'px'; 116 }else{ 117 picker.style.display = 'none'; 118 } 119} 120 121/** 122 * Create a toolbar 123 * 124 * @param string tbid ID of the element where to insert the toolbar 125 * @param string edid ID of the editor textarea 126 * @param array tb Associative array defining the buttons 127 * @author Andreas Gohr <andi@splitbrain.org> 128 */ 129function initToolbar(tbid,edid,tb){ 130 var toolbar = document.getElementById(tbid); 131 var cnt = tb.length; 132 for(i=0; i<cnt; i++){ 133 // create new button and add to the toolbar 134 btn = createToolButton(tb[i]['icon'], 135 tb[i]['title'], 136 tb[i]['key']); 137 toolbar.appendChild(btn); 138 139 // add button action dependend on type 140 switch(tb[i]['type']){ 141 case 'format': 142 var sample = tb[i]['title']; 143 if(tb[i]['sample']) sample = tb[i]['sample']; 144 145 eval("btn.onclick = function(){insertTags('"+ 146 jsEscape(edid)+"','"+ 147 jsEscape(tb[i]['open'])+"','"+ 148 jsEscape(tb[i]['close'])+"','"+ 149 jsEscape(sample)+ 150 "');return false;}"); 151 break; 152 case 'insert': 153 eval("btn.onclick = function(){insertAtCarret('"+ 154 jsEscape(edid)+"','"+ 155 jsEscape(tb[i]['insert'])+ 156 "');return false;}"); 157 break; 158 case 'picker': 159 createPicker('picker'+i, 160 tb[i]['list'], 161 tb[i]['icobase'], 162 edid); 163 eval("btn.onclick = function(){showPicker('picker"+i+ 164 "',this);return false;}"); 165 break; 166 case 'popup': 167 eval("btn.onclick = function(){window.open('"+ 168 jsEscape(tb[i]['url'])+"','"+ 169 jsEscape(tb[i]['name'])+"','"+ 170 jsEscape(tb[i]['options'])+ 171 "');return false;}"); 172 break; 173 } // end switch 174 } // end for 175} 176 177/** 178 * Format selection 179 * 180 * Apply tagOpen/tagClose to selection in textarea, use sampleText instead 181 * of selection if there is none. Copied and adapted from phpBB 182 * 183 * @author phpBB development team 184 * @author MediaWiki development team 185 * @author Andreas Gohr <andi@splitbrain.org> 186 * @author Jim Raynor <jim_raynor@web.de> 187 */ 188function insertTags(edid,tagOpen, tagClose, sampleText) { 189 var txtarea = document.getElementById(edid); 190 // IE 191 if(document.selection && !is_gecko) { 192 var theSelection = document.selection.createRange().text; 193 var replaced = true; 194 if(!theSelection){ 195 replaced = false; 196 theSelection=sampleText; 197 } 198 txtarea.focus(); 199 200 // This has change 201 text = theSelection; 202 if(theSelection.charAt(theSelection.length - 1) == " "){// exclude ending space char, if any 203 theSelection = theSelection.substring(0, theSelection.length - 1); 204 r = document.selection.createRange(); 205 r.text = tagOpen + theSelection + tagClose + " "; 206 } else { 207 r = document.selection.createRange(); 208 r.text = tagOpen + theSelection + tagClose; 209 } 210 if(!replaced){ 211 r.moveStart('character',-text.length-tagClose.length); 212 r.moveEnd('character',-tagClose.length); 213 } 214 r.select(); 215 // Mozilla 216 } else if(txtarea.selectionStart || txtarea.selectionStart == '0') { 217 var replaced = false; 218 var startPos = txtarea.selectionStart; 219 var endPos = txtarea.selectionEnd; 220 if(endPos - startPos) replaced = true; 221 var scrollTop=txtarea.scrollTop; 222 var myText = (txtarea.value).substring(startPos, endPos); 223 if(!myText) { myText=sampleText;} 224 if(myText.charAt(myText.length - 1) == " "){ // exclude ending space char, if any 225 subst = tagOpen + myText.substring(0, (myText.length - 1)) + tagClose + " "; 226 } else { 227 subst = tagOpen + myText + tagClose; 228 } 229 txtarea.value = txtarea.value.substring(0, startPos) + subst + 230 txtarea.value.substring(endPos, txtarea.value.length); 231 txtarea.focus(); 232 233 //set new selection 234 if(replaced){ 235 var cPos=startPos+(tagOpen.length+myText.length+tagClose.length); 236 txtarea.selectionStart=cPos; 237 txtarea.selectionEnd=cPos; 238 }else{ 239 txtarea.selectionStart=startPos+tagOpen.length; 240 txtarea.selectionEnd=startPos+tagOpen.length+myText.length; 241 } 242 txtarea.scrollTop=scrollTop; 243 // All others 244 } else { 245 var copy_alertText=alertText; 246 var re1=new RegExp("\\$1","g"); 247 var re2=new RegExp("\\$2","g"); 248 copy_alertText=copy_alertText.replace(re1,sampleText); 249 copy_alertText=copy_alertText.replace(re2,tagOpen+sampleText+tagClose); 250 var text; 251 if (sampleText) { 252 text=prompt(copy_alertText); 253 } else { 254 text=""; 255 } 256 if(!text) { text=sampleText;} 257 text=tagOpen+text+tagClose; 258 //append to the end 259 txtarea.value += "\n"+text; 260 261 // in Safari this causes scrolling 262 if(!is_safari) { 263 txtarea.focus(); 264 } 265 266 } 267 // reposition cursor if possible 268 if (txtarea.createTextRange) txtarea.caretPos = document.selection.createRange().duplicate(); 269} 270 271/* 272 * Insert the given value at the current cursor position 273 * 274 * @see http://www.alexking.org/index.php?content=software/javascript/content.php 275 */ 276function insertAtCarret(edid,value){ 277 var field = document.getElementById(edid); 278 279 //IE support 280 if (document.selection) { 281 field.focus(); 282 if(opener == null){ 283 sel = document.selection.createRange(); 284 }else{ 285 sel = opener.document.selection.createRange(); 286 } 287 sel.text = value; 288 //MOZILLA/NETSCAPE support 289 }else if (field.selectionStart || field.selectionStart == '0') { 290 var startPos = field.selectionStart; 291 var endPos = field.selectionEnd; 292 var scrollTop = field.scrollTop; 293 field.value = field.value.substring(0, startPos) 294 + value 295 + field.value.substring(endPos, field.value.length); 296 297 field.focus(); 298 var cPos=startPos+(value.length); 299 field.selectionStart=cPos; 300 field.selectionEnd=cPos; 301 field.scrollTop=scrollTop; 302 } else { 303 field.value += "\n"+value; 304 } 305 // reposition cursor if possible 306 if (field.createTextRange) field.caretPos = document.selection.createRange().duplicate(); 307} 308 309