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