Merge "Make variant selection menu toggleable by keyboard"
[lhc/web/wiklou.git] / resources / mediawiki.action / mediawiki.action.edit.js
index fc1b18d..38d4bb8 100644 (file)
@@ -1,17 +1,20 @@
+/**
+ * Interface for the classic edit toolbar.
+ *
+ * @class mw.toolbar
+ * @singleton
+ */
 ( function ( mw, $ ) {
-       var isReady, toolbar, currentFocused, queue, $toolbar, slice;
-
-       isReady = false;
-       queue = [];
-       $toolbar = false;
-       slice = Array.prototype.slice;
+       var toolbar, isReady, $toolbar, queue, slice, $currentFocused;
 
        /**
-        * Internal helper that does the actual insertion
-        * of the button into the toolbar.
-        * See mw.toolbar.addButton for parameter documentation.
+        * Internal helper that does the actual insertion of the button into the toolbar.
+        *
+        * See #addButton for parameter documentation.
+        *
+        * @private
         */
-       function insertButton( b /* imageFile */, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ) {
+       function insertButton( b, speedTip, tagOpen, tagClose, sampleText, imageId ) {
                // Backwards compatibility
                if ( typeof b !== 'object' ) {
                        b = {
                                tagOpen: tagOpen,
                                tagClose: tagClose,
                                sampleText: sampleText,
-                               imageId: imageId,
-                               selectText: selectText
+                               imageId: imageId
                        };
                }
-               var $image = $( '<img>', {
+               var $image = $( '<img>' ).attr( {
                        width : 23,
                        height: 22,
                        src   : b.imageFile,
                        id    : b.imageId || undefined,
                        'class': 'mw-toolbar-editbutton'
                } ).click( function () {
-                       toolbar.insertTags( b.tagOpen, b.tagClose, b.sampleText, b.selectText );
+                       toolbar.insertTags( b.tagOpen, b.tagClose, b.sampleText );
                        return false;
                } );
 
                $toolbar.append( $image );
-               return true;
        }
 
+       isReady = false;
+       $toolbar = false;
+       /**
+        * @private
+        * @property {Array}
+        * Contains button objects (and for backwards compatibilty, it can
+        * also contains an arguments array for insertButton).
+        */
+       queue = [];
+       slice = queue.slice;
+
        toolbar = {
+
                /**
                 * Add buttons to the toolbar.
+                *
                 * Takes care of race conditions and time-based dependencies
                 * by placing buttons in a queue if this method is called before
                 * the toolbar is created.
-                * @param {Object} button: Object with the following properties:
-                * - imageFile
-                * - speedTip
-                * - tagOpen
-                * - tagClose
-                * - sampleText
-                * - imageId
-                * - selectText
-                * For compatiblity, passing the above as separate arguments
+                *
+                * For compatiblity, passing the properties listed below as separate arguments
                 * (in the listed order) is also supported.
+                *
+                * @param {Object} button Object with the following properties:
+                * @param {string} button.imageFile
+                * @param {string} button.speedTip
+                * @param {string} button.tagOpen
+                * @param {string} button.tagClose
+                * @param {string} button.sampleText
+                * @param {string} [button.imageId]
                 */
                addButton: function () {
                        if ( isReady ) {
                                queue.push( slice.call( arguments ) );
                        }
                },
+               /**
+                * Example usage:
+                *     addButtons( [ { .. }, { .. }, { .. } ] );
+                *     addButtons( { .. }, { .. } );
+                *
+                * @param {Object|Array} [buttons...] An array of button objects or the first
+                *  button object in a list of variadic arguments.
+                */
+               addButtons: function ( buttons ) {
+                       if ( !$.isArray( buttons ) ) {
+                               buttons = slice.call( arguments );
+                       }
+                       if ( isReady ) {
+                               $.each( buttons, function () {
+                                       insertButton( this );
+                               } );
+                       } else {
+                               // Push each button into the queue
+                               queue.push.apply( queue, buttons );
+                       }
+               },
 
                /**
-                * Apply tagOpen/tagClose to selection in textarea,
-                * use sampleText instead of selection if there is none.
+                * Apply tagOpen/tagClose to selection in currently focused textarea.
+                *
+                * Uses `sampleText` if selection is empty.
+                *
+                * @param {string} tagOpen
+                * @param {string} tagClose
+                * @param {string} sampleText
                 */
                insertTags: function ( tagOpen, tagClose, sampleText ) {
-                       if ( currentFocused && currentFocused.length ) {
-                               currentFocused.textSelection(
+                       if ( $currentFocused && $currentFocused.length ) {
+                               $currentFocused.textSelection(
                                        'encapsulateSelection', {
-                                               'pre': tagOpen,
-                                               'peri': sampleText,
-                                               'post': tagClose
+                                               pre: tagOpen,
+                                               peri: sampleText,
+                                               post: tagClose
                                        }
                                );
                        }
        // Explose API publicly
        mw.toolbar = toolbar;
 
-       $( document ).ready( function () {
-               var buttons, i, b, $iframe;
+       $( function () {
+               var buttons, i, b, $iframe, editBox, scrollTop, $editForm;
 
                // currentFocus is used to determine where to insert tags
-               currentFocused = $( '#wpTextbox1' );
+               $currentFocused = $( '#wpTextbox1' );
 
                // Populate the selector cache for $toolbar
                $toolbar = $( '#toolbar' );
                buttons = [].concat( queue, window.mwCustomEditButtons );
                // Clear queue
                queue.length = 0;
+
                for ( i = 0; i < buttons.length; i++ ) {
                        b = buttons[i];
                        if ( $.isArray( b ) ) {
                                // Forwarded arguments array from mw.toolbar.addButton
                                insertButton.apply( toolbar, b );
                        } else {
-                               // Raw object from legacy mwCustomEditButtons
+                               // Raw object from mw.toolbar.addButtons or mwCustomEditButtons
                                insertButton( b );
                        }
                }
 
                // This causes further calls to addButton to go to insertion directly
-               // instead of to the toolbar.buttons queue.
+               // instead of to the queue.
                // It is important that this is after the one and only loop through
-               // the the toolbar.buttons queue
+               // the the queue
                isReady = true;
 
                // Make sure edit summary does not exceed byte limit
                $( '#wpSummary' ).byteLimit( 255 );
 
-               /**
-                * Restore the edit box scroll state following a preview operation,
-                * and set up a form submission handler to remember this state
-                */
-               ( function scrollEditBox() {
-                       var editBox, scrollTop, $editForm;
-
-                       editBox = document.getElementById( 'wpTextbox1' );
-                       scrollTop = document.getElementById( 'wpScrolltop' );
-                       $editForm = $( '#editform' );
-                       if ( $editForm.length && editBox && scrollTop ) {
-                               if ( scrollTop.value ) {
-                                       editBox.scrollTop = scrollTop.value;
-                               }
-                               $editForm.submit( function () {
-                                       scrollTop.value = editBox.scrollTop;
-                               });
+               // Restore the edit box scroll state following a preview operation,
+               // and set up a form submission handler to remember this state.
+               editBox = document.getElementById( 'wpTextbox1' );
+               scrollTop = document.getElementById( 'wpScrolltop' );
+               $editForm = $( '#editform' );
+               if ( $editForm.length && editBox && scrollTop ) {
+                       if ( scrollTop.value ) {
+                               editBox.scrollTop = scrollTop.value;
                        }
-               }() );
+                       $editForm.submit( function () {
+                               scrollTop.value = editBox.scrollTop;
+                       });
+               }
 
                // Apply to dynamically created textboxes as well as normal ones
                $( document ).on( 'focus', 'textarea, input:text', function () {
-                       currentFocused = $( this );
+                       $currentFocused = $( this );
                } );
 
-               // HACK: make currentFocused work with the usability iframe
+               // HACK: make $currentFocused work with the usability iframe
                // With proper focus detection support (HTML 5!) this'll be much cleaner
                // TODO: Get rid of this WikiEditor code from MediaWiki core!
                $iframe = $( '.wikiEditor-ui-text iframe' );
                                // for IE
                                .add( $iframe.get( 0 ).contentWindow.document.body )
                                .focus( function () {
-                                       currentFocused = $iframe;
+                                       $currentFocused = $iframe;
                                } );
                }
        });