fix typo
[dokuwiki.git] / lib / scripts / editor.js
blob0df556172a764ec90d09e5cbb450543e765dd361
1 /**
2  * The DokuWiki editor features
3  *
4  * These are the advanced features of the editor. It does NOT contain any
5  * code for the toolbar buttons and it functions. See toolbar.js for that.
6  */
8 var dw_editor = {
10     /**
11      * initialize the default editor functionality
12      *
13      * All other functions can also be called separately for non-default
14      * textareas
15      */
16     init: function(){
17         var $editor = jQuery('#wiki__text');
18         if($editor.length === 0) {
19             return;
20         }
22         dw_editor.initSizeCtl('#size__ctl',$editor);
24         if($editor.attr('readOnly')) {
25             return;
26         }
28         $editor.keydown(dw_editor.keyHandler);
30     },
32     /**
33      * Add the edit window size and wrap controls
34      *
35      * Initial values are read from cookie if it exists
36      *
37      * @param selector ctlarea the div to place the controls
38      * @param selector editor  the textarea to control
39      */
40     initSizeCtl: function(ctlarea,editor){
41         var $ctl      = jQuery(ctlarea),
42             $textarea = jQuery(editor);
44         if($ctl.length === 0 || $textarea.length === 0) {
45             return;
46         }
48         $textarea.css('height', DokuCookie.getValue('sizeCtl') || '300px');
50         var wrp = DokuCookie.getValue('wrapCtl');
51         if(wrp){
52             dw_editor.setWrap($textarea[0], wrp);
53         } // else use default value
55         jQuery.each([
56             ['larger', function(){dw_editor.sizeCtl(editor,100);}],
57             ['smaller', function(){dw_editor.sizeCtl(editor,-100);}],
58             ['wrap', function(){dw_editor.toggleWrap(editor);}]
59         ], function (_, img) {
60             jQuery(document.createElement('img'))
61                 .attr('src', DOKU_BASE+'lib/images/' + img[0] + '.gif')
62                 .attr('alt', '')
63                 .on('click', img[1])
64                 .appendTo($ctl);
65         });
66     },
68     /**
69      * This sets the vertical size of the editbox and adjusts the cookie
70      *
71      * @param selector editor  the textarea to control
72      * @param int val          the relative value to resize in pixel
73      */
74     sizeCtl: function(editor,val){
75         var $textarea = jQuery(editor),
76             height = parseInt($textarea.css('height')) + val;
77         $textarea.css('height', height+'px');
78         DokuCookie.setValue('sizeCtl',$textarea.css('height'));
79     },
81     /**
82      * Toggle the wrapping mode of the editor textarea and adjusts the
83      * cookie
84      *
85      * @param selector editor  the textarea to control
86      */
87     toggleWrap: function(editor){
88         var $textarea = jQuery(editor),
89             wrap = $textarea.attr('wrap');
90         dw_editor.setWrap($textarea[0],
91                           (wrap && wrap.toLowerCase() == 'off') ? 'soft' : 'off');
92         DokuCookie.setValue('wrapCtl',$textarea.attr('wrap'));
93     },
95     /**
96      * Set the wrapping mode of a textarea
97      *
98      * @author Fluffy Convict <fluffyconvict@hotmail.com>
99      * @author <shutdown@flashmail.com>
100      * @link   http://news.hping.org/comp.lang.javascript.archive/12265.html
101      * @link   https://bugzilla.mozilla.org/show_bug.cgi?id=41464
102      * @param  DomObject textarea
103      * @param  string wrapAttrValue
104      */
105     setWrap: function(textarea, wrapAttrValue){
106         textarea.setAttribute('wrap', wrapAttrValue);
108         // Fix display for mozilla
109         var parNod = textarea.parentNode;
110         var nxtSib = textarea.nextSibling;
111         parNod.removeChild(textarea);
112         parNod.insertBefore(textarea, nxtSib);
113     },
115     /**
116      * Make intended formattings easier to handle
117      *
118      * Listens to all key inputs and handle indentions
119      * of lists and code blocks
120      *
121      * Currently handles space, backspace, enter and
122      * ctrl-enter presses
123      *
124      * @author Andreas Gohr <andi@splitbrain.org>
125      * @fixme handle tabs
126      * @param event e - the key press event object
127      */
128     keyHandler: function(e){
129         if(jQuery.inArray(e.keyCode,[8, 10, 13, 32]) === -1) {
130             return;
131         }
132         var selection = DWgetSelection(this);
133         if(selection.getLength() > 0) {
134             return; //there was text selected, keep standard behavior
135         }
136         var search    = "\n"+this.value.substr(0,selection.start);
137         var linestart = Math.max(search.lastIndexOf("\n"),
138                                  search.lastIndexOf("\r")); //IE workaround
139         search = search.substr(linestart);
141         if((e.keyCode == 13 || e.keyCode == 10) && e.ctrlKey) { // Ctrl-Enter (With Chrome workaround)
142             // Submit current edit
143             jQuery('#edbtn__save').trigger('click');
144             e.preventDefault(); // prevent enter key
145             return false;
146         }else if(e.keyCode == 13){ // Enter
147             // keep current indention for lists and code
148             var match = search.match(/(\n  +([\*-] ?)?)/);
149             if(match){
150                 var scroll = this.scrollHeight;
151                 var match2 = search.match(/^\n  +[\*-]\s*$/);
152                 // Cancel list if the last item is empty (i. e. two times enter)
153                 if (match2 && this.value.substr(selection.start).match(/^($|\r?\n)/)) {
154                     this.value = this.value.substr(0, linestart) + "\n" +
155                                  this.value.substr(selection.start);
156                     selection.start = linestart + 1;
157                     selection.end = linestart + 1;
158                     DWsetSelection(selection);
159                 } else {
160                     insertAtCarret(this.id,match[1]);
161                 }
162                 this.scrollTop += (this.scrollHeight - scroll);
163                 e.preventDefault(); // prevent enter key
164                 return false;
165             }
166         }else if(e.keyCode == 8){ // Backspace
167             // unindent lists
168             var match = search.match(/(\n  +)([*-] ?)$/);
169             if(match){
170                 var spaces = match[1].length-1;
172                 if(spaces > 3){ // unindent one level
173                     this.value = this.value.substr(0,linestart)+
174                                  this.value.substr(linestart+2);
175                     selection.start = selection.start - 2;
176                     selection.end   = selection.start;
177                 }else{ // delete list point
178                     this.value = this.value.substr(0,linestart)+
179                                  this.value.substr(selection.start);
180                     selection.start = linestart;
181                     selection.end   = linestart;
182                 }
183                 DWsetSelection(selection);
184                 e.preventDefault(); // prevent backspace
185                 return false;
186             }
187         }else if(e.keyCode == 32){ // Space
188             // intend list item
189             var match = search.match(/(\n  +)([*-] )$/);
190             if(match){
191                 this.value = this.value.substr(0,linestart)+'  '+
192                              this.value.substr(linestart);
193                 selection.start = selection.start + 2;
194                 selection.end   = selection.start;
195                 DWsetSelection(selection);
196                 e.preventDefault(); // prevent space
197                 return false;
198             }
199         }
200     }
205 jQuery(dw_editor.init);