1/** 2 * Functions for text editing (toolbar stuff) 3 * 4 * @todo most of the stuff in here should be revamped and then moved to toolbar.js 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 * @author Michal Rezler <m.rezler@centrum.cz> 15 */ 16function createToolButton(icon,label,key,id,classname){ 17 var $ = jQuery; 18 var btn = $('<button>'); 19 var ico = $('<img />'); 20 21 // preapare the basic button stuff 22 btn.attr('class', 'toolbutton'); 23 if(classname){ 24 btn.attr('class', 'toolbutton '+classname); 25 } 26 27 btn.attr('title', label); 28 if(key){ 29 btn.attr('title', label + ' ['+key.toUpperCase()+']') 30 .attr('accessKey', key); 31 } 32 33 // set IDs if given 34 if(id){ 35 btn.attr('id', id); 36 ico.attr('id', id+'_ico'); 37 } 38 39 // create the icon and add it to the button 40 if(icon.substr(0,1) == '/'){ 41 ico.attr('src', icon); 42 }else{ 43 ico.attr('src', DOKU_BASE+'lib/images/toolbar/'+icon); 44 } 45 btn.append(ico); 46 47 // we have to return a javascript object (for compatibility reasons) 48 return btn[0]; 49} 50 51/** 52 * Creates a picker window for inserting text 53 * 54 * The given list can be an associative array with text,icon pairs 55 * or a simple list of text. Style the picker window through the picker 56 * class or the picker buttons with the pickerbutton class. Picker 57 * windows are appended to the body and created invisible. 58 * 59 * @param string id the ID to assign to the picker 60 * @param array props the properties for the picker 61 * @param string edid the ID of the textarea 62 * @rteurn DOMobject the created picker 63 * @author Andreas Gohr <andi@splitbrain.org> 64 */ 65function createPicker(id,props,edid){ 66 var icobase = props['icobase']; 67 var list = props['list']; 68 var $ = jQuery; 69 70 // create the wrapping div 71 var picker = $('<div></div>'); 72 73 var className = 'picker'; 74 if(props['class']){ 75 className += ' '+props['class']; 76 } 77 78 picker.attr('class', className) 79 .attr('id', id) 80 .css('position', 'absolute') 81 .css('marginLeft', '-10000px') // no display:none, to keep access keys working 82 .css('marginTop', '-10000px'); 83 84 for(var key in list){ 85 if (!list.hasOwnProperty(key)) continue; 86 87 if(isNaN(key)){ 88 // associative array -> treat as image/value pairs 89 var btn = $('<button>'); 90 btn.attr('class', 'pickerbutton') 91 .attr('title', key); 92 93 var ico = $('<img>'); 94 if (list[key].substr(0,1) == '/') { 95 var src = list[key]; 96 } else { 97 var src = DOKU_BASE+'lib/images/'+icobase+'/'+list[key]; 98 } 99 100 ico.attr('src', src); 101 btn.append(ico); 102 103 btn.bind('click', bind(pickerInsert, key, edid)); 104 picker.append(btn); 105 }else if (typeof (list[key]) == 'string'){ 106 // a list of text -> treat as text picker 107 var btn = $('<button>'); 108 btn.attr('class', 'pickerbutton') 109 .attr('title', list[key]); 110 111 var txt = $(document.createTextNode(list[key])); 112 btn.append(txt); 113 114 btn.bind('click', bind(pickerInsert, list[key], edid)); 115 116 picker.append(btn); 117 }else{ 118 // a list of lists -> treat it as subtoolbar 119 initToolbar(picker,edid,list); 120 break; // all buttons handled already 121 } 122 123 } 124 var body = $('body'); 125 body.append(picker); 126 127 // we have to return a javascript object (for compatibility reasons) 128 return picker[0]; 129} 130 131/** 132 * Called by picker buttons to insert Text and close the picker again 133 * 134 * @author Andreas Gohr <andi@splitbrain.org> 135 */ 136function pickerInsert(text,edid){ 137 insertAtCarret(edid,text); 138 pickerClose(); 139} 140 141/** 142 * Add button action for signature button 143 * 144 * @param DOMElement btn Button element to add the action to 145 * @param array props Associative array of button properties 146 * @param string edid ID of the editor textarea 147 * @return boolean If button should be appended 148 * @author Gabriel Birke <birke@d-scribe.de> 149 */ 150function addBtnActionSignature(btn, props, edid) { 151 if(typeof(SIG) != 'undefined' && SIG != ''){ 152 btn.bind('click', bind(insertAtCarret,edid,SIG)); 153 return true; 154 } 155 return false; 156} 157 158/** 159 * Determine the current section level while editing 160 * 161 * @author Andreas Gohr <gohr@cosmocode.de> 162 */ 163function currentHeadlineLevel(textboxId){ 164 var field = $(textboxId); 165 var selection = getSelection(field); 166 var search = "\n"+field.value.substr(0,selection.start); 167 var lasthl = search.lastIndexOf("\n=="); 168 if(lasthl == -1 && field.form.prefix){ 169 // we need to look in prefix context 170 search = field.form.prefix.value; 171 lasthl = search.lastIndexOf("\n=="); 172 } 173 search = search.substr(lasthl+1,6); 174 175 if(search == '======') return 1; 176 if(search.substr(0,5) == '=====') return 2; 177 if(search.substr(0,4) == '====') return 3; 178 if(search.substr(0,3) == '===') return 4; 179 if(search.substr(0,2) == '==') return 5; 180 181 return 0; 182} 183 184 185/** 186 * global var used for not saved yet warning 187 */ 188window.textChanged = false; 189 190/** 191 * Delete the draft before leaving the page 192 */ 193function deleteDraft() { 194 if (is_opera) return; 195 if (window.keepDraft) return; 196 197 // remove a possibly saved draft using ajax 198 var dwform = jQuery('#dw__editform'); 199 if(dwform.length != 0) { 200 201 jQuery.post( 202 DOKU_BASE + 'lib/exe/ajax.php', 203 { 204 call: 'draftdel', 205 id: jQuery('#dw__editform input[name=id]').val() 206 } 207 ); 208 } 209} 210 211/** 212 * Activate "not saved" dialog, add draft deletion to page unload, 213 * add handlers to monitor changes 214 * 215 * Sets focus to the editbox as well 216 */ 217addInitEvent(function () { 218 var $ = jQuery; 219 var editform = $('#dw__editform'); 220 if (editform.length == 0) return; 221 222 var edit_text = $('#wiki__text'); 223 if (edit_text.length > 0) { 224 if(edit_text.attr('readOnly')) return; 225 226 // set focus and place cursor at the start 227 var sel = getSelection(edit_text.get(0)); 228 sel.start = 0; 229 sel.end = 0; 230 setSelection(sel); 231 edit_text.focus(); 232 } 233 234 var checkfunc = function() { 235 textChanged = true; //global var 236 summaryCheck(); 237 }; 238 239 editform.change(checkfunc); 240 editform.keydown(checkfunc); 241 242 window.onbeforeunload = function(){ 243 if(window.textChanged) { 244 return LANG.notsavedyet; 245 } 246 }; 247 window.onunload = deleteDraft; 248 249 // reset change memory var on submit 250 $('#edbtn__save').click( 251 function() { 252 window.onbeforeunload = ''; 253 textChanged = false; 254 } 255 ); 256 $('#edbtn__preview').click( 257 function() { 258 window.onbeforeunload = ''; 259 textChanged = false; 260 window.keepDraft = true; // needed to keep draft on page unload 261 } 262 ); 263 264 var summary = $('#edit__summary'); 265 summary.change(summaryCheck); 266 summary.keyup(summaryCheck); 267 268 if (textChanged) summaryCheck(); 269}); 270 271/** 272 * Checks if a summary was entered - if not the style is changed 273 * 274 * @author Andreas Gohr <andi@splitbrain.org> 275 */ 276function summaryCheck(){ 277 var sum = jQuery('#edit__summary'); 278 279 if (sum.val() === '') { 280 sum.attr('class', 'missing'); 281 } else{ 282 sum.attr('class', 'edit'); 283 } 284} 285