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