From: Timo Tijhof Date: Sat, 21 Jul 2012 23:49:46 +0000 (-0700) Subject: mw.toolbar: Clean up the API of the classic toolbar. X-Git-Tag: 1.31.0-rc.0~22969^2 X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/pie.php?a=commitdiff_plain;h=0452a5c167b0bb9df56a0d7e18bb39353e199049;p=lhc%2Fweb%2Fwiklou.git mw.toolbar: Clean up the API of the classic toolbar. * Several methods were added here recently during 1.20 development that should not have been public methods. * Also in the creation of this new module (replacing the old mwCustomEditButtons) a design flaw was made. Instead of using a key-value pair object, the signature was changed to a tentacle function with 7 (for callers, unnamed) arguments. * Changed it back with the compatibility fix the other way around. So everything is backwards compatible. * Moved to local scope: - buttons queue - $toolbar - insertButton These were recently introduced during 1.20 development but not meant to be public. When used too early or too late from outside the module it will break or be ignored. For example $toolbar is false before dom ready, buttons queue is ignored after domready, insertButton will break if called before dom ready because the target element doesn't exist yet. These are not bugs, but result of calling internal methods before they are initialized. The public API takes care of these state differences by using the queue and the dom ready handler. Scripts should (and do) only use the addButton API. * Kept: - addButton - insertTags - init (empty b/c function, was already there) * Improved: - addButton: Now takes an object as well, just like mwCustomEditButtons used to do. - Cache Array.prototype.slice instead of re-grabbing from a new dummy array. - Store buttons[i] in a local variable in both cases, not just for legacy. Saves 2 property lookups. Minor gain, but in this case it was already going to be stored in a local variable, so might as well do it in the other case. * Fixes: - Clear queue array after it has been used. Though in practice it should never happen that it is iterated over twice, just in case. - Added comment to init() function explaining where it is used. - Updated closure arguments per code conventions. - Made it a position-top module so that it actually can be used before the document is ready. * Example usages tested: // Legacy way from wikibits.js: // Has to be done before document ready window.mwCustomEditButtons[window.mwCustomEditButtons.length] = { imageFile: 'http://placehold.it/23x22', speedTip: 'tool tip', tagOpen: 'x-', tagClose: '-y' }; // mw.toolbar: List of arguments mw.toolbar.addButton( 'http://placehold.it/23x22', 'tooltip', 'x-', '-y' ); // mw.toolbar: Object mw.toolbar.addButton({ imageFile: 'http://placehold.it/23x22', speedTip: 'tool tip', tagOpen: 'x-', tagClose: '-y' }); Change-Id: Id19819707c937c2c3144ad8177b75baa46f5073c --- diff --git a/resources/Resources.php b/resources/Resources.php index 0e85050bf2..9900ab1480 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -632,6 +632,7 @@ return array( 'jquery.textSelection', 'jquery.byteLimit', ), + 'position' => 'top', ), 'mediawiki.action.history' => array( 'scripts' => 'resources/mediawiki.action/mediawiki.action.history.js', diff --git a/resources/mediawiki.action/mediawiki.action.edit.js b/resources/mediawiki.action/mediawiki.action.edit.js index 14b845d9d5..bd07cd09bb 100644 --- a/resources/mediawiki.action/mediawiki.action.edit.js +++ b/resources/mediawiki.action/mediawiki.action.edit.js @@ -1,42 +1,74 @@ -( function ( $, mw ) { - var isReady, toolbar, currentFocused; +( function ( mw, $ ) { + var isReady, toolbar, currentFocused, queue, $toolbar, slice; isReady = false; + queue = []; + $toolbar = false; + slice = Array.prototype.slice; + + /** + * Internal helper that does the actual insertion + * of the button into the toolbar. + * See mw.toolbar.addButton for parameter documentation. + */ + function insertButton( b /* imageFile */, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ) { + // Backwards compatibility + if ( typeof b !== 'object' ) { + b = { + imageFile: b, + speedTip: speedTip, + tagOpen: tagOpen, + tagClose: tagClose, + sampleText: sampleText, + imageId: imageId, + selectText: selectText + }; + } + var $image = $('', { + width : 23, + height: 22, + src : b.imageFile, + alt : b.speedTip, + title : b.speedTip, + id : b.imageId || undefined, + 'class': 'mw-toolbar-editbutton' + } ).click( function () { + toolbar.insertTags( b.tagOpen, b.tagClose, b.sampleText, b.selectText ); + return false; + } ); + + $toolbar.append( $image ); + return true; + } toolbar = { - $toolbar: false, - buttons: [], /** - * If you want to add buttons, use - * mw.toolbar.addButton( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ); + * 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 + * (in the listed order) is also supported. */ addButton: function () { if ( isReady ) { - toolbar.insertButton.apply( toolbar, arguments ); + insertButton.apply( toolbar, arguments ); } else { - toolbar.buttons.push( [].slice.call( arguments ) ); - } - }, - insertButton: function ( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ) { - var image = $('', { - width : 23, - height: 22, - src : imageFile, - alt : speedTip, - title : speedTip, - id : imageId || '', - 'class': 'mw-toolbar-editbutton' - } ).click( function () { - mw.toolbar.insertTags( tagOpen, tagClose, sampleText, selectText ); - return false; - } ); - - toolbar.$toolbar.append( image ); - return true; + // Convert arguments list to array + queue.push( slice.call( arguments ) ); + } }, /** - * apply tagOpen/tagClose to selection in textarea, + * Apply tagOpen/tagClose to selection in textarea, * use sampleText instead of selection if there is none. */ insertTags: function ( tagOpen, tagClose, sampleText, selectText ) { @@ -51,7 +83,8 @@ } }, - // For backwards compatibility + // For backwards compatibility, + // Called from EditPage.php, maybe in other places as well. init: function () {} }; @@ -59,29 +92,30 @@ window.addButton = toolbar.addButton; window.insertTags = toolbar.insertTags; - // Explose publicly + // Explose API publicly mw.toolbar = toolbar; $( document ).ready( function () { - var buttons, i, c, iframe; + var buttons, i, b, iframe; // currentFocus is used to determine where to insert tags currentFocused = $( '#wpTextbox1' ); - // Populate the selector cache for $toolbar - toolbar.$toolbar = $( '#toolbar' ); + // Populate the selector cache for $toolbar + $toolbar = $( '#toolbar' ); // Legacy: Merge buttons from mwCustomEditButtons - buttons = [].concat( toolbar.buttons, window.mwCustomEditButtons ); + buttons = [].concat( queue, window.mwCustomEditButtons ); + // Clear queue + queue.length = 0; for ( i = 0; i < buttons.length; i++ ) { - if ( $.isArray( buttons[i] ) ) { - // Passes our button array as arguments - toolbar.insertButton.apply( toolbar, buttons[i] ); + b = buttons[i]; + if ( $.isArray( b ) ) { + // Forwarded arguments array from mw.toolbar.addButton + insertButton.apply( toolbar, b ); } else { - // Legacy mwCustomEditButtons is an object - c = buttons[i]; - toolbar.insertButton( c.imageFile, c.speedTip, c.tagOpen, - c.tagClose, c.sampleText, c.imageId, c.selectText ); + // Raw object from legacy mwCustomEditButtons + insertButton( b ); } } @@ -131,4 +165,4 @@ } }); -}( jQuery, mediaWiki ) ); +}( mediaWiki, jQuery ) );