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