Index: branches/resourceloader/phase3/resources/mw/mw.legacy.edit.js |
— | — | @@ -0,0 +1,258 @@ |
| 2 | +/* |
| 3 | + * Legacy emulation for the now depricated changepassword.js |
| 4 | + * |
| 5 | + * Ported by: Trevor Parscal |
| 6 | + */ |
| 7 | + |
| 8 | +( function( $ ) { |
| 9 | + |
| 10 | +$.extend( mw.legacy, { |
| 11 | + 'currentFocused': null, |
| 12 | + /** |
| 13 | + * Generates the actual toolbar buttons with localized text we use it to avoid creating the toolbar |
| 14 | + * where javascript is not enabled |
| 15 | + */ |
| 16 | + 'addButton': function( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId ) { |
| 17 | + // Don't generate buttons for browsers which don't fully support it. |
| 18 | + mw.legacy.mwEditButtons.push( { |
| 19 | + 'imageId': imageId, |
| 20 | + 'imageFile': imageFile, |
| 21 | + 'speedTip': speedTip, |
| 22 | + 'tagOpen': tagOpen, |
| 23 | + 'tagClose': tagClose, |
| 24 | + 'sampleText': sampleText |
| 25 | + } ); |
| 26 | + }, |
| 27 | + /** |
| 28 | + * Generates the actual toolbar buttons with localized text we use it to avoid creating the toolbar where JavaScript |
| 29 | + * is not enabled |
| 30 | + */ |
| 31 | + 'mwInsertEditButton': function( parent, item ) { |
| 32 | + var $image = $( '<img />' ) |
| 33 | + .attr( { |
| 34 | + 'width': 23, |
| 35 | + 'height': 22, |
| 36 | + 'class': 'mw-toolbar-editbutton', |
| 37 | + 'id': item.imageId ? item.imageId : null, |
| 38 | + 'src': = item.imageFile, |
| 39 | + 'border': 0, |
| 40 | + 'alt': item.speedTip, |
| 41 | + 'title': item.speedTip |
| 42 | + } ) |
| 43 | + .css( 'cursor', 'pointer' ) |
| 44 | + .click( function() { |
| 45 | + mw.legacy.insertTags( item.tagOpen, item.tagClose, item.sampleText ); |
| 46 | + // Click tracking |
| 47 | + if ( typeof $.trackAction != 'undefined' ) { |
| 48 | + $.trackAction( 'oldedit.' + item.speedTip.replace( / /g, "-" ) ); |
| 49 | + } |
| 50 | + return false; |
| 51 | + } ) |
| 52 | + .appendTo( $( parent ) ); |
| 53 | + return true; |
| 54 | + }, |
| 55 | + /** |
| 56 | + * Sets up the toolbar |
| 57 | + */ |
| 58 | + 'mwSetupToolbar': function() { |
| 59 | + var $toolbar = $( '#toolbar' ); |
| 60 | + var $textbox = $( 'textarea' ).get( 0 ); |
| 61 | + if ( !$toolbar.length || !$textbox.length ) { |
| 62 | + return false; |
| 63 | + } |
| 64 | + // Only check for selection capability if the textarea is visible - errors will occur otherwise - just because |
| 65 | + // the textarea is not visible, doesn't mean we shouldn't build out the toolbar though - it might have been |
| 66 | + // replaced with some other kind of control |
| 67 | + if ( |
| 68 | + $textbox.is( ':visible' ) && |
| 69 | + !( document.selection && document.selection.createRange ) && |
| 70 | + textboxes[0].selectionStart === null |
| 71 | + ) { |
| 72 | + return false; |
| 73 | + } |
| 74 | + for ( var i = 0; i < mw.legacy.mwEditButtons.length; i++ ) { |
| 75 | + mw.legacy.mwInsertEditButton( $toolbar, mw.legacy.mwEditButtons[i] ); |
| 76 | + } |
| 77 | + for ( var i = 0; i < mw.legacy.mwCustomEditButtons.length; i++ ) { |
| 78 | + mw.legacy.mwInsertEditButton( $toolbar, mw.legacy.mwCustomEditButtons[i] ); |
| 79 | + } |
| 80 | + return true; |
| 81 | + }, |
| 82 | + /** |
| 83 | + * Apply tagOpen/tagClose to selection in textarea, use sampleText instead of selection if there is none |
| 84 | + */ |
| 85 | + 'insertTags': function( tagOpen, tagClose, sampleText ) { |
| 86 | + function checkSelectedText() { |
| 87 | + if ( !selText ) { |
| 88 | + selText = sampleText; |
| 89 | + isSample = true; |
| 90 | + } else if ( selText.charAt( selText.length - 1 ) == ' ' ) { // exclude ending space char |
| 91 | + selText = selText.substring( 0, selText.length - 1 ); |
| 92 | + tagClose += ' '; |
| 93 | + } |
| 94 | + } |
| 95 | + var currentFocused = $( mw.legacy.currentFocused ); |
| 96 | + if ( |
| 97 | + typeof $.fn.textSelection != 'undefined' && |
| 98 | + ( $currentFocused.name().toLowerCase() == 'iframe' || $currentFocused.attr( 'id' ) == 'wpTextbox1' ) |
| 99 | + ) { |
| 100 | + $j( '#wpTextbox1' ).textSelection( |
| 101 | + 'encapsulateSelection', { 'pre': tagOpen, 'peri': sampleText, 'post': tagClose } |
| 102 | + ); |
| 103 | + return; |
| 104 | + } |
| 105 | + var $textarea; |
| 106 | + if ( $( 'form[name=editform]' ) { |
| 107 | + $textarea = $currentFocused; |
| 108 | + } else { |
| 109 | + // Some alternate form? take the first one we can find |
| 110 | + $textarea = $( 'textarea' ).get( 0 ); |
| 111 | + } |
| 112 | + var selText, isSample = false; |
| 113 | + // Text selection implementation for IE and Opera |
| 114 | + if ( document.selection && document.selection.createRange ) { |
| 115 | + // Save window scroll position |
| 116 | + if ( document.documentElement && document.documentElement.scrollTop ) { |
| 117 | + var winScroll = document.documentElement.scrollTop |
| 118 | + } else if ( document.body ) { |
| 119 | + var winScroll = document.body.scrollTop; |
| 120 | + } |
| 121 | + // Get current selection |
| 122 | + $textarea.focus(); |
| 123 | + var range = document.selection.createRange(); |
| 124 | + selText = range.text; |
| 125 | + // Insert tags |
| 126 | + checkSelectedText(); |
| 127 | + range.text = tagOpen + selText + tagClose; |
| 128 | + // Mark sample text as selected |
| 129 | + if ( isSample && range.moveStart ) { |
| 130 | + if ( window.opera ) { |
| 131 | + tagClose = tagClose.replace( /\n/g,'' ); |
| 132 | + } |
| 133 | + range.moveStart( 'character', - tagClose.length - selText.length ); |
| 134 | + range.moveEnd( 'character', - tagClose.length ); |
| 135 | + } |
| 136 | + range.select(); |
| 137 | + // Restore window scroll position |
| 138 | + if ( document.documentElement && document.documentElement.scrollTop ) { |
| 139 | + document.documentElement.scrollTop = winScroll; |
| 140 | + } else if ( document.body ) { |
| 141 | + document.body.scrollTop = winScroll; |
| 142 | + } |
| 143 | + } |
| 144 | + // Text selection implementation for Mozilla, Chrome and Safari |
| 145 | + else if ( $textarea[0].selectionStart || $textarea[0].selectionStart == '0' ) { |
| 146 | + // Save textarea scroll position |
| 147 | + var textScroll = $textarea.scrollTop; |
| 148 | + // Get current selection |
| 149 | + $textarea.focus(); |
| 150 | + var startPos = $textarea[0].selectionStart; |
| 151 | + var endPos = $textarea[0].selectionEnd; |
| 152 | + selText = $textarea.value.substring( startPos, endPos ); |
| 153 | + // Insert tags |
| 154 | + checkSelectedText(); |
| 155 | + $textarea.val( |
| 156 | + $textarea.val().substring( 0, startPos ) + |
| 157 | + tagOpen + selText + tagClose + |
| 158 | + $textarea.val().substring( endPos, $textarea.val().length ) |
| 159 | + ); |
| 160 | + // Set new selection |
| 161 | + if ( isSample ) { |
| 162 | + $textarea[0].selectionStart = startPos + tagOpen.length; |
| 163 | + $textarea[0].selectionEnd = startPos + tagOpen.length + selText.length; |
| 164 | + } else { |
| 165 | + $textarea[0].selectionStart = startPos + tagOpen.length + selText.length + tagClose.length; |
| 166 | + $textarea[0].selectionEnd = $textarea[0].selectionStart; |
| 167 | + } |
| 168 | + // Restore textarea scroll position |
| 169 | + $textarea[0].scrollTop = textScroll; |
| 170 | + } |
| 171 | + }, |
| 172 | + /** |
| 173 | + * Restore the edit box scroll state following a preview operation, |
| 174 | + * and set up a form submission handler to remember this state |
| 175 | + */ |
| 176 | + 'scrollEditBox': function() { |
| 177 | + var $textbox = $( '#wpTextbox1' ); |
| 178 | + var $scrollTop = $( '#wpScrolltop' ); |
| 179 | + var $editForm = $( '#editform' ); |
| 180 | + if ( $editForm.length && $textbox.length && $scrollTop.length ) { |
| 181 | + if ( scrollTop.val() ) { |
| 182 | + $textbox.scrollTop = $scrollTop.val(); |
| 183 | + } |
| 184 | + $editForm.submit( function() { |
| 185 | + $scrollTop.val( $textbox.scrollTop ); |
| 186 | + } ); |
| 187 | + } |
| 188 | + } |
| 189 | +} ); |
| 190 | + |
| 191 | +/* Initialization */ |
| 192 | + |
| 193 | +$( document ).ready( function() { |
| 194 | + mw.legacy.scrollEditBox(); |
| 195 | + mw.legacy.mwSetupToolbar(); |
| 196 | + mw.legacy.currentFocused = $( '#wpTextbox1' ).get( 0 ); |
| 197 | + // http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html focus does not bubble normally, but using a |
| 198 | + // trick we can do event delegation on the focus event on all text inputs to make the toolbox usable on all of them |
| 199 | + $( '#editform' ).focus( function() { |
| 200 | + $(this).each( function( e ) { |
| 201 | + var elm = e.target || e.srcElement; |
| 202 | + if ( !elm ) { |
| 203 | + return; |
| 204 | + } |
| 205 | + var tagName = elm.tagName.toLowerCase(); |
| 206 | + var type = elm.type || ''; |
| 207 | + if ( tagName !== 'textarea' && tagName !== 'input' ) { |
| 208 | + return; |
| 209 | + } |
| 210 | + if ( tagName === 'input' && type.toLowerCase() !== 'text' ) { |
| 211 | + return; |
| 212 | + } |
| 213 | + mw.legacy.currentFocused = elm; |
| 214 | + } ); |
| 215 | + } ); |
| 216 | + // HACK: make currentFocused work with the usability iframe - with proper focus detection support (HTML 5!) this'll |
| 217 | + // be much cleaner |
| 218 | + var $iframe = $j( '.wikiEditor-ui-text iframe' ); |
| 219 | + if ( $iframe.length > 0 ) { |
| 220 | + $j( $iframe.get( 0 ).contentWindow.document ) |
| 221 | + // For IE |
| 222 | + .add( $iframe.get( 0 ).contentWindow.document.body ) |
| 223 | + .focus( function() { mw.legacy.currentFocused = $iframe.get( 0 ); } ); |
| 224 | + } |
| 225 | + // Make sure edit summary does not exceed byte limit |
| 226 | + var $summary = $( '#wpSummary' ); |
| 227 | + if ( !$summary.length ) { |
| 228 | + return; |
| 229 | + } |
| 230 | + // L must be capitalized in length |
| 231 | + $summary.get( 0 ).maxLength = 250; |
| 232 | + $summary.keypress( function( e ) { |
| 233 | + // First check to see if this is actually a character key being pressed. Based on key-event info from |
| 234 | + // http://unixpapa.com/js/key.html note === sign, if undefined, still could be a real key |
| 235 | + if ( e.which === 0 || e.charCode === 0 || e.ctrlKey || e.altKey || e.metaKey ) { |
| 236 | + // A special key (backspace, etc) so don't interefere. |
| 237 | + return true; |
| 238 | + } |
| 239 | + // This basically figures out how many bytes a utf-16 string (which is what js sees) will take in utf-8 by |
| 240 | + // replacing a 2 byte character with 2 *'s, etc, and counting that. Note, surogate (\uD800-\uDFFF) characters |
| 241 | + // are counted as 2 bytes, since theres two of them and the actual character takes 4 bytes in utf-8 (2*2=4). |
| 242 | + // Might not work perfectly in edge cases such as such as illegal sequences, but that should never happen. |
| 243 | + len = summary.value |
| 244 | + .replace(/[\u0080-\u07FF\uD800-\uDFFF]/g, '**') |
| 245 | + .replace(/[\u0800-\uD7FF\uE000-\uFFFF]/g, '***') |
| 246 | + .length; |
| 247 | + // 247 as this doesn't count character about to be inserted. |
| 248 | + if ( len > 247 ) { |
| 249 | + if ( e.preventDefault ) { |
| 250 | + e.preventDefault(); |
| 251 | + } |
| 252 | + // IE |
| 253 | + e.returnValue = false; |
| 254 | + return false; |
| 255 | + } |
| 256 | + } ); |
| 257 | +} ); |
| 258 | + |
| 259 | +} )( jQuery ); |
\ No newline at end of file |