From d9022f63880ce039446fba8364f68e656b7bf4cb Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Thu, 3 May 2012 13:01:35 +0200 Subject: Update to MediaWiki 1.19.0 --- .../mediawiki.action/mediawiki.action.edit.js | 165 ++++++++----- .../mediawiki.action/mediawiki.action.history.js | 135 +++++++--- .../mediawiki.action.view.dblClickEdit.js | 12 + .../mediawiki.action.view.metadata.js | 2 +- .../mediawiki.action.watch.ajax.js | 271 ++++++++++----------- 5 files changed, 342 insertions(+), 243 deletions(-) create mode 100644 resources/mediawiki.action/mediawiki.action.view.dblClickEdit.js (limited to 'resources/mediawiki.action') diff --git a/resources/mediawiki.action/mediawiki.action.edit.js b/resources/mediawiki.action/mediawiki.action.edit.js index b121d34f..e685ca94 100644 --- a/resources/mediawiki.action/mediawiki.action.edit.js +++ b/resources/mediawiki.action/mediawiki.action.edit.js @@ -1,101 +1,134 @@ -(function( $ ) { - // currentFocus is used to determine where to insert tags - var currentFocused = $( '#wpTextbox1' ); - - mw.toolbar = { - $toolbar : $( '#toolbar' ), - buttons : [], - // If you want to add buttons, use - // mw.toolbar.addButton( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ); - addButton : function() { - this.buttons.push( [].slice.call( arguments ) ); +( function ( $, mw ) { + var isReady, toolbar, currentFocused; + + isReady = false; + + toolbar = { + $toolbar: false, + buttons: [], + /** + * If you want to add buttons, use + * mw.toolbar.addButton( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ); + */ + addButton: function () { + if ( isReady ) { + toolbar.insertButton.apply( toolbar, arguments ); + } else { + toolbar.buttons.push( [].slice.call( arguments ) ); + } }, - insertButton : function( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ) { + insertButton: function ( imageFile, speedTip, tagOpen, tagClose, sampleText, imageId, selectText ) { var image = $('', { - width : 23, - height : 22, - src : imageFile, - alt : speedTip, - title : speedTip, - id : imageId || '', + width : 23, + height: 22, + src : imageFile, + alt : speedTip, + title : speedTip, + id : imageId || '', 'class': 'mw-toolbar-editbutton' - } ).click( function() { + } ).click( function () { mw.toolbar.insertTags( tagOpen, tagClose, sampleText, selectText ); return false; } ); - this.$toolbar.append( image ); + toolbar.$toolbar.append( image ); return true; }, - // apply tagOpen/tagClose to selection in textarea, - // use sampleText instead of selection if there is none - insertTags : function( tagOpen, tagClose, sampleText, selectText) { - if ( currentFocused.length ) { + /** + * apply tagOpen/tagClose to selection in textarea, + * use sampleText instead of selection if there is none. + */ + insertTags: function ( tagOpen, tagClose, sampleText, selectText ) { + if ( currentFocused && currentFocused.length ) { currentFocused.textSelection( - 'encapsulateSelection', { 'pre': tagOpen, 'peri': sampleText, 'post': tagClose } + 'encapsulateSelection', { + 'pre': tagOpen, + 'peri': sampleText, + 'post': tagClose + } ); } - }, - init : function() { - // Legacy - // Merge buttons from mwCustomEditButtons - var buttons = [].concat( this.buttons, window.mwCustomEditButtons ); - for ( var i = 0; i < buttons.length; i++ ) { - if ( $.isArray( buttons[i] ) ) { - // Passes our button array as arguments - mw.toolbar.insertButton.apply( this, buttons[i] ); - } else { - // Legacy mwCustomEditButtons is an object - var c = buttons[i]; - mw.toolbar.insertButton( c.imageFile, c.speedTip, c.tagOpen, c.tagClose, c.sampleText, c.imageId, c.selectText ); - } + }, + + // For backwards compatibility + init: function () {} + }; + + // Legacy (for compatibility with the code previously in skins/common.edit.js) + window.addButton = toolbar.addButton; + window.insertTags = toolbar.insertTags; + + // Explose publicly + mw.toolbar = toolbar; + + $( document ).ready( function () { + var buttons, i, c, iframe; + + // currentFocus is used to determine where to insert tags + currentFocused = $( '#wpTextbox1' ); + + // Populate the selector cache for $toolbar + toolbar.$toolbar = $( '#toolbar' ); + + // Legacy: Merge buttons from mwCustomEditButtons + buttons = [].concat( toolbar.buttons, window.mwCustomEditButtons ); + for ( i = 0; i < buttons.length; i++ ) { + if ( $.isArray( buttons[i] ) ) { + // Passes our button array as arguments + toolbar.insertButton.apply( toolbar, buttons[i] ); + } 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 ); } - return true; } - }; - //Legacy - window.addButton = mw.toolbar.addButton; - window.insertTags = mw.toolbar.insertTags; + // This causes further calls to addButton to go to insertion directly + // instead of to the toolbar.buttons queue. + // It is important that this is after the one and only loop through + // the the toolbar.buttons queue + isReady = true; + + // Make sure edit summary does not exceed byte limit + $( '#wpSummary' ).byteLimit( 250 ); - //make sure edit summary does not exceed byte limit - $( '#wpSummary' ).byteLimit( 250 ); - - $( document ).ready( function() { /** * Restore the edit box scroll state following a preview operation, * and set up a form submission handler to remember this state */ - var scrollEditBox = function() { - var editBox = document.getElementById( 'wpTextbox1' ); - var scrollTop = document.getElementById( 'wpScrolltop' ); - var $editForm = $( '#editform' ); - if( $editForm.length && editBox && scrollTop ) { - if( scrollTop.value ) { + ( 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() { + $editForm.submit( function () { scrollTop.value = editBox.scrollTop; }); } - }; - scrollEditBox(); - - // Create button bar - mw.toolbar.init(); - - $( 'textarea, input:text' ).focus( function() { + }() ); + + $( 'textarea, input:text' ).focus( function () { currentFocused = $(this); }); // HACK: make currentFocused work with the usability iframe // With proper focus detection support (HTML 5!) this'll be much cleaner - var iframe = $( '.wikiEditor-ui-text iframe' ); + iframe = $( '.wikiEditor-ui-text iframe' ); if ( iframe.length > 0 ) { $( iframe.get( 0 ).contentWindow.document ) - .add( iframe.get( 0 ).contentWindow.document.body ) // for IE - .focus( function() { currentFocused = iframe; } ); + // for IE + .add( iframe.get( 0 ).contentWindow.document.body ) + .focus( function () { + currentFocused = iframe; + } ); } }); -})(jQuery); + +}( jQuery, mediaWiki ) ); diff --git a/resources/mediawiki.action/mediawiki.action.history.js b/resources/mediawiki.action/mediawiki.action.history.js index 1b5b3a00..76b0e6cd 100644 --- a/resources/mediawiki.action/mediawiki.action.history.js +++ b/resources/mediawiki.action/mediawiki.action.history.js @@ -1,53 +1,126 @@ -/* +/** * JavaScript for History action */ -jQuery( function( $ ) { - var $lis = $( 'ul#pagehistory li' ); - var updateDiffRadios = function() { +jQuery( document ).ready( function ( $ ) { + var $historyCompareForm = $( '#mw-history-compare' ), + $historySubmitter, + $lis = $( '#pagehistory > li' ); + + /** + * @context {Element} input + * @param e {jQuery.Event} + */ + function updateDiffRadios() { var diffLi = false, // the li where the diff radio is checked oldLi = false; // the li where the oldid radio is checked if ( !$lis.length ) { return true; } - $lis.removeClass( 'selected' ); - $lis.each( function() { - var $this = $(this); - var $inputs = $this.find( 'input[type="radio"]' ); - if ( $inputs.length !== 2 ) { + + $lis + .removeClass( 'selected' ) + .each( function () { + var $li = $(this), + $inputs = $li.find( 'input[type="radio"]' ), + $oldidRadio = $inputs.filter( '[name="oldid"]' ).eq(0), + $diffRadio = $inputs.filter( '[name="diff"]' ).eq(0); + + if ( !$oldidRadio.length || !$diffRadio.length ) { return true; } - // this row has a checked radio button - if ( $inputs.get(0).checked ) { + if ( $oldidRadio.prop( 'checked' ) ) { oldLi = true; - $this.addClass( 'selected' ); - $inputs.eq(0).css( 'visibility', 'visible' ); - $inputs.eq(1).css( 'visibility', 'hidden' ); - } else if ( $inputs.get(1).checked ) { + $li.addClass( 'selected' ); + $oldidRadio.css( 'visibility', 'visible' ); + $diffRadio.css( 'visibility', 'hidden' ); + + } else if ( $diffRadio.prop( 'checked' ) ) { diffLi = true; - $this.addClass( 'selected' ); - $inputs.eq(0).css( 'visibility', 'hidden' ); - $inputs.eq(1).css( 'visibility', 'visible' ); + $li.addClass( 'selected' ); + $oldidRadio.css( 'visibility', 'hidden' ); + $diffRadio.css( 'visibility', 'visible' ); + + // This list item has neither checked } else { - // no radio is checked in this row + // We're below the selected radios if ( diffLi && oldLi ) { - // We're below the selected radios - $inputs.eq(0).css( 'visibility', 'visible' ); - $inputs.eq(1).css( 'visibility', 'hidden' ); - } else if ( diffLi ) { - // We're between the selected radios - $inputs.css( 'visibility', 'visible' ); + $oldidRadio.css( 'visibility', 'visible' ); + $diffRadio.css( 'visibility', 'hidden' ); + + // We're between the selected radios + } else if ( diffLi ) { + $diffRadio.css( 'visibility', 'visible' ); + $oldidRadio.css( 'visibility', 'visible' ); + + // We're above the selected radios } else { - // We're above the selected radios - $inputs.eq(1).css( 'visibility', 'visible' ); - $inputs.eq(0).css( 'visibility', 'hidden' ); + $diffRadio.css( 'visibility', 'visible' ); + $oldidRadio.css( 'visibility', 'hidden' ); } } }); + return true; - }; + } + + $lis.find( 'input[name="diff"], input[name="oldid"]' ).click( updateDiffRadios ); - $( '#pagehistory li input[name="diff"], #pagehistory li input[name="oldid"]' ).click( updateDiffRadios ); + // Set initial state updateDiffRadios(); -}); \ No newline at end of file + + + // Prettify url output for HistoryAction submissions, + // to cover up action=historysubmit construction. + + // Ideally we'd use e.target instead of $historySubmitter, but e.target points + // to the form element for submit actions, so. + $historyCompareForm.find( '.historysubmit' ).click( function () { + $historySubmitter = $(this); + } ); + + // On submit we clone the form element, remove unneeded fields in the clone + // that pollute the query parameter with stuff from the other "use case", + // and then submit the clone. + // Without the cloning we'd be changing the real form, which is slower, could make + // the page look broken for a second in slow browsers and might show the form broken + // again when coming back from a "next" page. + $historyCompareForm.submit( function ( e ) { + var $copyForm, $copyRadios, $copyAction; + + if ( $historySubmitter ) { + $copyForm = $historyCompareForm.clone(); + $copyRadios = $copyForm.find( '#pagehistory > li' ).find( 'input[name="diff"], input[name="oldid"]' ); + $copyAction = $copyForm.find( '> [name="action"]'); + + // Remove action=historysubmit and ids[..]=.. + if ( $historySubmitter.hasClass( 'mw-history-compareselectedversions-button' ) ) { + $copyAction.remove(); + $copyForm.find( 'input[name^="ids["]:checked' ).prop( 'checked', false ); + + // Remove diff=&oldid=, change action=historysubmit to revisiondelete, remove revisiondelete + } else if ( $historySubmitter.hasClass( 'mw-history-revisiondelete-button' ) ) { + $copyRadios.remove(); + $copyAction.val( $historySubmitter.attr( 'name' ) ); + $copyForm.find( ':submit' ).remove(); + } + + // IE7 doesn't do submission from an off-DOM clone, so insert hidden into document first + // Also remove potentially conflicting id attributes that we don't need anyway + $copyForm + .css( 'display', 'none' ) + .find('[id]') + .removeAttr('id') + .end() + .insertAfter( $historyCompareForm ) + .submit(); + + e.preventDefault(); + return false; // Because the submit is special, return false as well. + } + + // Continue natural browser handling other wise + return true; + } ); +} ); diff --git a/resources/mediawiki.action/mediawiki.action.view.dblClickEdit.js b/resources/mediawiki.action/mediawiki.action.view.dblClickEdit.js new file mode 100644 index 00000000..b1d906f6 --- /dev/null +++ b/resources/mediawiki.action/mediawiki.action.view.dblClickEdit.js @@ -0,0 +1,12 @@ +/** + * This module enables double-click-to-edit functionality + */ +jQuery( document ).ready( function( $ ) { + var url = $( '#ca-edit a' ).attr( 'href' ); + if ( url ) { + mw.util.$content.dblclick( function( e ) { + e.preventDefault(); + window.location = url; + } ); + } +} ); diff --git a/resources/mediawiki.action/mediawiki.action.view.metadata.js b/resources/mediawiki.action/mediawiki.action.view.metadata.js index 378dd155..b791cabd 100644 --- a/resources/mediawiki.action/mediawiki.action.view.metadata.js +++ b/resources/mediawiki.action/mediawiki.action.view.metadata.js @@ -14,7 +14,7 @@ jQuery( document ).ready( function( $ ) { return; } - var $row = $( '' ); + var $row = $( '' ); var $col = $( '' ); var $link = $( '', { diff --git a/resources/mediawiki.action/mediawiki.action.watch.ajax.js b/resources/mediawiki.action/mediawiki.action.watch.ajax.js index 93aa29c9..f5f09f52 100644 --- a/resources/mediawiki.action/mediawiki.action.watch.ajax.js +++ b/resources/mediawiki.action/mediawiki.action.watch.ajax.js @@ -1,174 +1,155 @@ /** * Animate watch/unwatch links to use asynchronous API requests to - * watch pages, rather than clicking on links. Requires jQuery. + * watch pages, rather than navigating to a different URI. */ -( function( $ ) { -var $links; - -var setLinkText = function( $link, action ) { - if ( action == 'watch' || action == 'unwatch' ) { - // save the accesskey from the title - var keyCommand = $link.attr( 'title' ).match( /\[.*?\]$/ ) ? $link.attr( 'title' ).match( /\[.*?\]$/ )[0] : ''; - $link.attr( 'title', mw.msg( 'tooltip-ca-' + action ) + ' ' + keyCommand ); - } - if ( $link.data( 'icon' ) ) { - $link.attr( 'alt', mw.msg( action ) ); - if ( action == 'watching' || action == 'unwatching' ) { +( function ( $, mw, undefined ) { + +/** + * The name of the page to watch or unwatch. + */ +var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) ); + +/** + * Update the link text, link href attribute and (if applicable) + * "loading" class. + * + * @param $link {jQuery} Anchor tag of (un)watch link + * @param action {String} One of 'watch', 'unwatch'. + * @param state {String} [optional] 'idle' or 'loading'. Default is 'idle'. + */ +function updateWatchLink( $link, action, state ) { + // message keys 'watch', 'watching', 'unwatch' or 'unwatching'. + var msgKey = state === 'loading' ? action + 'ing' : action, + accesskeyTip = $link.attr( 'title' ).match( mw.util.tooltipAccessKeyRegexp ), + $li = $link.closest( 'li' ); + + $link + .text( mw.msg( msgKey ) ) + .attr( 'title', mw.msg( 'tooltip-ca-' + action ) + + ( accesskeyTip ? ' ' + accesskeyTip[0] : '' ) + ) + .attr( 'href', mw.util.wikiScript() + '?' + $.param({ + title: title, + action: action + }) + ); + + // Special case for vector icon + if ( $li.hasClass( 'icon' ) ) { + if ( state === 'loading' ) { $link.addClass( 'loading' ); } else { $link.removeClass( 'loading' ); } - } else { - $link.html( mw.msg( action ) ); } -}; - -var errorHandler = function( $link ) { - - // Reset link text to whatever it was before we switching it to the '(un)watch'+ing message. - setLinkText( $link, $link.data( 'action' ) ); - - // Format error message - var cleanTitle = mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ); - var link = mw.html.element( - 'a', { - 'href': mw.util.wikiGetlink( mw.config.get( 'wgPageName' ) ), - 'title': cleanTitle - }, cleanTitle - ); - var msg = mw.msg( 'watcherrortext', link ); - - // Report to user about the error - mw.util.jsMessage( msg, 'watch' ); -}; +} /** - * Process the result of the API watch action. - * - * @param response Data object from API request. - * @param $link jQuery object of the watch link. - * @return Boolean true on success, false otherwise. + * @todo This should be moved somewhere more accessible. + * @param url {String} + * @return {String} The extracted action, defaults to 'view'. */ -var processResult = function( response, $link ) { - - if ( ( 'error' in response ) || !response.watch ) { - errorHandler( $link ); - return false; +function mwUriGetAction( url ) { + var actionPaths = mw.config.get( 'wgActionPaths' ), + key, parts, m, action; + + // @todo: Does MediaWiki give action path or query param + // precedence ? If the former, move this to the bottom + action = mw.util.getParamValue( 'action', url ); + if ( action !== null ) { + return action; } - var watchResponse = response.watch; - - // To ensure we set the same status for all watch links with the - // same target we trigger a custom event on *all* watch links. - if ( watchResponse.watched !== undefined ) { - $links.trigger( 'mw-ajaxwatch', [watchResponse.title, 'watch', $link] ); - } else if ( watchResponse.unwatched !== undefined ) { - $links.trigger( 'mw-ajaxwatch', [watchResponse.title, 'unwatch', $link] ); - } else { - // Either we got an error code or it just plain broke. - window.location.href = $link[0].href; - return false; + for ( key in actionPaths ) { + if ( actionPaths.hasOwnProperty( key ) ) { + parts = actionPaths[key].split( '$1' ); + for ( i = 0; i < parts.length; i += 1 ) { + parts[i] = $.escapeRE( parts[i] ); + } + m = new RegExp( parts.join( '(.+)' ) ).exec( url ); + if ( m && m[1] ) { + return key; + } + + } } - mw.util.jsMessage( watchResponse.message, 'watch' ); - - // Bug 12395 - update the watch checkbox on edit pages when the - // page is watched or unwatched via the tab. - if ( watchResponse.watched !== undefined ) { - $( '#wpWatchthis' ).attr( 'checked', 'checked' ); - } else { - $( '#wpWatchthis' ).removeAttr( 'checked' ); - } - return true; -}; + return 'view'; +} $( document ).ready( function() { - $links = $( '.mw-watchlink a, a.mw-watchlink' ); - // BC with older skins - $links = $links - .add( '#ca-watch a, #ca-unwatch a, a#mw-unwatch-link1, ' + - 'a#mw-unwatch-link2, a#mw-watch-link2, a#mw-watch-link1' ); - // allowing people to add inline animated links is a little scary - $links = $links.filter( ':not( #bodyContent *, #content * )' ); + var $links = $( '.mw-watchlink a, a.mw-watchlink, ' + + '#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' + + '#mw-unwatch-link2, #mw-watch-link2, #mw-watch-link1' ); - $links.each( function() { - var $link = $( this ); - var link = this; - $link - .data( 'icon', $link.closest( 'li' ).hasClass( 'icon' ) ) - .data( 'action', mw.util.getParamValue( 'action', link.href ) == 'unwatch' ? 'unwatch' : 'watch' ); - var title = mw.util.getParamValue( 'title', link.href ); - $link.data( 'target', title.replace( /_/g, ' ' ) ); - }); + // Allowing people to add inline animated links is a little scary + $links = $links.filter( ':not( #bodyContent *, #content * )' ); - $links.click( function( event ) { - var $link = $( this ); + $links.click( function( e ) { + var $link, api, + action = mwUriGetAction( this.href ); - if ( !mw.config.get( 'wgEnableWriteAPI' ) ) { - // Lazy initialization so we don't toss up - // ActiveX warnings on initial page load - // for IE 6 users with security settings. - $links.unbind( 'click' ); + if ( action !== 'watch' && action !== 'unwatch' ) { + // Could not extract target action from link url, + // let native browsing handle it further return true; } - - setLinkText( $link, $link.data( 'action' ) + 'ing' ); - - var reqData = { - 'action': 'watch', - 'format': 'json', - 'title': $link.data( 'target' ), - 'token': mw.user.tokens.get( 'watchToken' ), - // API return contains a localized data.watch.message string. - 'uselang': mw.config.get( 'wgUserLanguage' ) - }; - - if ( $link.data( 'action' ) == 'unwatch' ) { - reqData.unwatch = ''; - } - - $.ajax({ - url: mw.util.wikiScript( 'api' ), - dataType: 'json', - type: 'POST', - data: reqData, - success: function( data, textStatus, xhr ) { - processResult( data, $link ); + e.preventDefault(); + e.stopPropagation(); + + $link = $( this ); + + updateWatchLink( $link, action, 'loading' ); + + api = new mw.Api(); + api[action]( + title, + // Success + function( watchResponse ) { + var otherAction = action === 'watch' ? 'unwatch' : 'watch', + $li = $link.closest( 'li' ); + + mw.util.jsMessage( watchResponse.message, 'ajaxwatch' ); + + // Set link to opposite + updateWatchLink( $link, otherAction ); + + // Most common ID style + if ( $li.prop( 'id' ) === 'ca-' + otherAction || $li.prop( 'id' ) === 'ca-' + action ) { + $li.prop( 'id', 'ca-' + otherAction ); + } + + // Bug 12395 - update the watch checkbox on edit pages when the + // page is watched or unwatched via the tab. + if ( watchResponse.watched !== undefined ) { + $( '#wpWatchthis' ).prop( 'checked', true ); + } else { + $( '#wpWatchthis' ).removeProp( 'checked' ); + } }, - error: function(){ - processResult( {}, $link ); - } - }); + // Error + function(){ + + // Reset link to non-loading mode + updateWatchLink( $link, action ); + + // Format error message + var cleanTitle = title.replace( /_/g, ' ' ); + var link = mw.html.element( + 'a', { + 'href': mw.util.wikiGetlink( title ), + 'title': cleanTitle + }, cleanTitle + ); + var html = mw.msg( 'watcherrortext', link ); + + // Report to user about the error + mw.util.jsMessage( html, 'ajaxwatch' ); - return false; - }); - - // When a request returns, a custom event 'mw-ajaxwatch' is triggered - // on *all* watch links, so they can be updated if necessary - $links.bind( 'mw-ajaxwatch', function( event, target, action, $link ) { - var foo = $link.data( 'target' ); - if ( $link.data( 'target' ) == target ) { - var otheraction = action == 'watch' - ? 'unwatch' - : 'watch'; - - $link.data( 'action', otheraction ); - setLinkText( $link, otheraction ); - $link.attr( 'href', - mw.config.get( 'wgScript' ) - + '?title=' + mw.util.wikiUrlencode( mw.config.get( 'wgPageName' ) ) - + '&action=' + otheraction - ); - if ( $link.closest( 'li' ).attr( 'id' ) == 'ca-' + action ) { - $link.closest( 'li' ).attr( 'id', 'ca-' + otheraction ); - // update the link text with the new message - $link.text( mw.msg( otheraction ) ); } - } - - return false; + ); }); }); -})( jQuery ); +})( jQuery, mediaWiki ); -- cgit v1.2.2