(bug 29105) Splitlines completely messes up selection of inserted text. This is not...
[mediawiki.git] / skins / common / edit.js
blob732aa921520bd0845b33714f8bb6a4f9ee2cfcf5
1 // This file is still referenced from
2 //  tests/selenium/data/SimpleSeleniumTestDB.sql
3 //  includes/specials/SpecialUpload.php
4 //  /extensions/SemanticForms/specials/SF_UploadWindow2.php
5 window.currentFocused = undefined;
7 // this function adds a toolbar button to the mwEditButtons list
8 window.addButton = function( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ) {
9         // Don't generate buttons for browsers which don't fully
10         // support it.
11         mwEditButtons.push({
12                 'imageId': imageId,
13                 'imageFile': imageFile,
14                 'speedTip': speedTip,
15                 'tagOpen': tagOpen,
16                 'tagClose': tagClose,
17                 'sampleText': sampleText,
18                 'selectText': selectText
19         });
22 // this function adds one toolbar button from a mwEditButtons/mwCustomEditButtons item
23 window.mwInsertEditButton = function( parent, item ) {
24         var image = document.createElement( 'img' );
25         image.width = 23;
26         image.height = 22;
27         image.className = 'mw-toolbar-editbutton';
28         if ( item.imageId ) {
29                 image.id = item.imageId;
30         }
31         image.src = item.imageFile;
32         image.border = 0;
33         image.alt = item.speedTip;
34         image.title = item.speedTip;
35         image.style.cursor = 'pointer';
36         image.onclick = function() {
37                 insertTags( item.tagOpen, item.tagClose, item.sampleText, item.selectText );
38                 // click tracking
39                 if ( ( typeof $ != 'undefined' )  && ( typeof $.trackAction != 'undefined' ) ) {
40                         $.trackAction( 'oldedit.' + item.speedTip.replace(/ /g, '-') );
41                 }
42                 return false;
43         };
45         parent.appendChild( image );
46         return true;
49 // this function generates the actual toolbar buttons with localized text
50 // we use it to avoid creating the toolbar where javascript is not enabled
51 window.mwSetupToolbar = function() {
52         var toolbar = document.getElementById( 'toolbar' );
53         var i = 0;
54         if ( !toolbar ) {
55                 return false;
56         }
58         // Don't generate buttons for browsers which don't fully
59         // support it.
60         // but don't assume wpTextbox1 is always here
61         var textboxes = document.getElementsByTagName( 'textarea' );
62         if ( !textboxes.length ) {
63                 // No toolbar if we can't find any textarea
64                 return false;
65         }
66         // Only check for selection capability if the textarea is visible - errors will occur otherwise - just because
67         // the textarea is not visible, doesn't mean we shouldn't build out the toolbar though - it might have been replaced
68         // with some other kind of control
69         if ( textboxes[0].style.display != 'none' ) {
70                 if ( !( document.selection && document.selection.createRange )
71                         && textboxes[0].selectionStart === null ) {
72                         return false;
73                 }
74         }
75         for ( i = 0; i < mwEditButtons.length; i++ ) {
76                 mwInsertEditButton( toolbar, mwEditButtons[i] );
77         }
78         for ( i = 0; i < mwCustomEditButtons.length; i++ ) {
79                 mwInsertEditButton( toolbar, mwCustomEditButtons[i] );
80         }
81         return true;
84 // apply tagOpen/tagClose to selection in textarea,
85 // use sampleText instead of selection if there is none
86 window.insertTags = function( tagOpen, tagClose, sampleText, selectText) {
87         if ( typeof $ != 'undefined' && typeof $.fn.textSelection != 'undefined' && currentFocused &&
88                         ( currentFocused.nodeName.toLowerCase() == 'iframe' || currentFocused.id == 'wpTextbox1' ) ) {
89                 $( '#wpTextbox1' ).textSelection(
90                         'encapsulateSelection', { 'pre': tagOpen, 'peri': sampleText, 'post': tagClose }
91                 );
92                 return;
93         }
94         var txtarea;
95         if ( document.editform ) {
96                 txtarea = currentFocused;
97         } else {
98                 // some alternate form? take the first one we can find
99                 var areas = document.getElementsByTagName( 'textarea' );
100                 txtarea = areas[0];
101         }
102         var selText, isSample = false;
104         function checkSelectedText() {
105                 if ( !selText ) {
106                         selText = sampleText;
107                         isSample = true;
108                 } else if ( selText.charAt(selText.length - 1) == ' ' ) { // exclude ending space char
109                         selText = selText.substring(0, selText.length - 1);
110                         tagClose += ' ';
111                 }
112         }
114         if ( document.selection  && document.selection.createRange ) { // IE/Opera
115                 // save window scroll position
116                 var winScroll = null;
117                 if ( document.documentElement && document.documentElement.scrollTop ) {
118                         winScroll = document.documentElement.scrollTop;
119                 } else if ( document.body ) {
120                         winScroll = document.body.scrollTop;
121                 }
122                 // get current selection
123                 txtarea.focus();
124                 var range = document.selection.createRange();
125                 selText = range.text;
126                 // insert tags
127                 checkSelectedText();
128                 range.text = tagOpen + selText + tagClose;
129                 // mark sample text as selected if not switched off by option
130                 if ( selectText !== false ) {
131                         if ( isSample && range.moveStart ) {
132                                 if ( window.opera ) {
133                                         tagClose = tagClose.replace(/\n/g,'');
134                                 }
135                                 range.moveStart('character', - tagClose.length - selText.length);
136                                 range.moveEnd('character', - tagClose.length);
137                         }
138                         range.select();
139                 }
140                 // restore window scroll position
141                 if ( document.documentElement && document.documentElement.scrollTop ) {
142                         document.documentElement.scrollTop = winScroll;
143                 } else if ( document.body ) {
144                         document.body.scrollTop = winScroll;
145                 }
147         } else if ( txtarea.selectionStart || txtarea.selectionStart == '0' ) { // Mozilla
148                 // save textarea scroll position
149                 var textScroll = txtarea.scrollTop;
150                 // get current selection
151                 txtarea.focus();
152                 var startPos = txtarea.selectionStart;
153                 var endPos = txtarea.selectionEnd;
154                 selText = txtarea.value.substring( startPos, endPos );
155                 // insert tags
156                 checkSelectedText();
157                 txtarea.value = txtarea.value.substring(0, startPos)
158                         + tagOpen + selText + tagClose
159                         + txtarea.value.substring(endPos, txtarea.value.length);
160                 // set new selection
161                 if ( isSample && ( selectText !== false )) {
162                         txtarea.selectionStart = startPos + tagOpen.length;
163                         txtarea.selectionEnd = startPos + tagOpen.length + selText.length;
164                 } else {
165                         txtarea.selectionStart = startPos + tagOpen.length + selText.length + tagClose.length;
166                         txtarea.selectionEnd = txtarea.selectionStart;
167                 }
168                 // restore textarea scroll position
169                 txtarea.scrollTop = textScroll;
170         }
175  * Restore the edit box scroll state following a preview operation,
176  * and set up a form submission handler to remember this state
177  */
178 window.scrollEditBox = function() {
179         var editBox = document.getElementById( 'wpTextbox1' );
180         var scrollTop = document.getElementById( 'wpScrolltop' );
181         var editForm = document.getElementById( 'editform' );
182         if( editForm && editBox && scrollTop ) {
183                 if( scrollTop.value ) {
184                         editBox.scrollTop = scrollTop.value;
185                 }
186                 addHandler( editForm, 'submit', function() {
187                         scrollTop.value = editBox.scrollTop;
188                 } );
189         }
191 hookEvent( 'load', scrollEditBox );
192 hookEvent( 'load', mwSetupToolbar );
193 hookEvent( 'load', function() {
194         currentFocused = document.getElementById( 'wpTextbox1' );
195         // http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
196         // focus does not bubble normally, but using a trick we can do event delegation
197         // on the focus event on all text inputs to make the toolbox usable on all of them
198         var editForm = document.getElementById( 'editform' );
199         if ( !editForm ) {
200                 return;
201         }
202         function onfocus( e ) {
203                 var elm = e.target || e.srcElement;
204                 if ( !elm ) {
205                         return;
206                 }
207                 var tagName = elm.tagName.toLowerCase();
208                 var type = elm.type || '';
209                 if ( tagName !== 'textarea' && tagName !== 'input' ) {
210                         return;
211                 }
212                 if ( tagName === 'input' && type.toLowerCase() !== 'text' ) {
213                         return;
214                 }
216                 currentFocused = elm;
217         }
219         if ( editForm.addEventListener ) {
220                 // Gecko, WebKit, Opera, etc... (all standards compliant browsers)
221                 editForm.addEventListener( 'focus', onfocus, true ); // This MUST be true to work
222         } else if ( editForm.attachEvent ) {
223                 // IE needs a specific trick here since it doesn't support the standard
224                 editForm.attachEvent( 'onfocusin', function() { onfocus( event ); } );
225         }
226         
227         // HACK: make currentFocused work with the usability iframe
228         // With proper focus detection support (HTML 5!) this'll be much cleaner
229         if ( typeof $ != 'undefined' ) {
230                 var iframe = $( '.wikiEditor-ui-text iframe' );
231                 if ( iframe.length > 0 ) {
232                         $( iframe.get( 0 ).contentWindow.document )
233                                 .add( iframe.get( 0 ).contentWindow.document.body ) // for IE
234                                 .focus( function() { currentFocused = iframe.get( 0 ); } );
235                 }
236         }
238 } );