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