(bug 7851) Implement mediawiki.page.patrol.ajax
authorMarius Hoch <hoo@online.de>
Wed, 3 Oct 2012 01:33:55 +0000 (03:33 +0200)
committerMarius Hoch <hoo@online.de>
Tue, 13 Nov 2012 22:09:38 +0000 (23:09 +0100)
Implement AJAX patrolling with the new mediawiki.page.patrol.ajax
module, which makes use of the API via mediawiki.api.

During the patrol process a spinner (created by jquery.spinner)
shows up and after it a suitable message gets shown via
mediawiki.notify.

Depending on whether we had success or not the link then turns up
again or the brackets completely disappear just like on a normal page view.

On top of adding the module, I've changed the following:
- Added the patrol token to the ResourceLoaderUserTokensModule.
- Registered messages 'markedaspatrollednotify' and
  'markedaspatrollederrornotify'.

Change-Id: I472357566dda0ab572c20e2e4b87508b0f2f4c73

RELEASE-NOTES-1.21
includes/Article.php
includes/diff/DifferenceEngine.php
includes/resourceloader/ResourceLoaderUserTokensModule.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc
resources/Resources.php
resources/mediawiki.page/mediawiki.page.patrol.ajax.js [new file with mode: 0644]

index 881f008..31ce2e3 100644 (file)
@@ -35,6 +35,7 @@ production.
   tables that have a corresponding ORMTable class.
 * (bug 40876) Icon for PSD (Adobe Photoshop) file types.
 * (bug 40641) Implemented Special:Version/Credits with a list of contributors.
+* (bug 7851) Implemented one-click AJAX patrolling.
 
 === Bug fixes in 1.21 ===
 * (bug 40353) SpecialDoubleRedirect should support interwiki redirects.
index 169dd03..1d2b023 100644 (file)
@@ -1044,6 +1044,8 @@ class Article extends Page {
         * If patrol is possible, output a patrol UI box. This is called from the
         * footer section of ordinary page views. If patrol is not possible or not
         * desired, does nothing.
+        * Side effect: When the patrol link is build, this method will call
+        * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax.
         */
        public function showPatrolFooter() {
                $request = $this->getContext()->getRequest();
@@ -1056,7 +1058,9 @@ class Article extends Page {
                }
 
                $token = $user->getEditToken( $rcid );
+
                $outputPage->preventClickjacking();
+               $outputPage->addModules( 'mediawiki.page.patrol.ajax' );
 
                $link = Linker::linkKnown(
                        $this->getTitle(),
index 0295f77..9afe69e 100644 (file)
@@ -421,8 +421,8 @@ class DifferenceEngine extends ContextSource {
        /**
         * Get a link to mark the change as patrolled, or '' if there's either no
         * revision to patrol or the user is not allowed to to it.
-        * Side effect: this method will call OutputPage::preventClickjacking()
-        * when a link is builded.
+        * Side effect: When the patrol link is build, this method will call
+        * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax.
         *
         * @return String
         */
@@ -463,6 +463,8 @@ class DifferenceEngine extends ContextSource {
                                // Build the link
                                if ( $rcid ) {
                                        $this->getOutput()->preventClickjacking();
+                                       $this->getOutput()->addModules( 'mediawiki.page.patrol.ajax' );
+
                                        $token = $this->getUser()->getEditToken( $rcid );
                                        $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown(
                                                $this->mNewPage,
index 62d096a..6d787c5 100644 (file)
@@ -43,7 +43,8 @@ class ResourceLoaderUserTokensModule extends ResourceLoaderModule {
 
                return array(
                        'editToken' => $wgUser->getEditToken(),
-                       'watchToken' => ApiQueryInfo::getWatchToken(null, null),
+                       'patrolToken' => ApiQueryRecentChanges::getPatrolToken( null, null ),
+                       'watchToken' => ApiQueryInfo::getWatchToken( null, null ),
                );
        }
 
index ec31872..5e33d62 100644 (file)
@@ -3810,6 +3810,8 @@ This is probably caused by a link to a blacklisted external site.',
 'markedaspatrollederror'              => 'Cannot mark as patrolled',
 'markedaspatrollederrortext'          => 'You need to specify a revision to mark as patrolled.',
 'markedaspatrollederror-noautopatrol' => 'You are not allowed to mark your own changes as patrolled.',
+'markedaspatrollednotify'             => 'This change to $1 has been marked as patrolled.',
+'markedaspatrollederrornotify'        => 'Marking as patrolled failed.',
 
 # Patrol log
 'patrol-log-page'      => 'Patrol log',
index 14e3886..709f1dd 100644 (file)
@@ -3645,6 +3645,8 @@ Used as link text, linked to '{{int:Prefixindex}}' page ([[Special:PrefixIndex]]
 
 # Patrolling
 'markedaspatrolledtext' => '{{Identical|Markedaspatrolled}}',
+'markedaspatrollednotify' => 'Notification shown after a change has been marked as patrolled, $1 is the page title',
+'markedaspatrollederrornotify' => 'Notification shown after marking a change as patrolled failed',
 
 # Patrol log
 'patrol-log-page' => '{{doc-logpage}}',
index eee9799..d7a396f 100644 (file)
@@ -2738,6 +2738,8 @@ $wgMessageStructure = array(
                'markedaspatrollederror',
                'markedaspatrollederrortext',
                'markedaspatrollederror-noautopatrol',
+               'markedaspatrollednotify',
+               'markedaspatrollederrornotify',
        ),
        'patrol-log' => array(
                'patrol-log-page',
index afa9bb2..80b9a76 100644 (file)
@@ -810,6 +810,23 @@ return array(
                ),
                'position' => 'top',
        ),
+       'mediawiki.page.patrol.ajax' => array(
+               'scripts' => 'resources/mediawiki.page/mediawiki.page.patrol.ajax.js',
+               'dependencies' => array(
+                       'mediawiki.page.startup',
+                       'mediawiki.api',
+                       'mediawiki.util',
+                       'mediawiki.Title',
+                       'mediawiki.notify',
+                       'jquery.spinner',
+                       'user.tokens'
+               ),
+               'messages' => array(
+                       'markedaspatrollednotify',
+                       'markedaspatrollederrornotify',
+                       'markedaspatrollederror-noautopatrol'
+               ),
+       ),
        'mediawiki.page.watch.ajax' => array(
                'scripts' => 'resources/mediawiki.page/mediawiki.page.watch.ajax.js',
                'dependencies' => array(
diff --git a/resources/mediawiki.page/mediawiki.page.patrol.ajax.js b/resources/mediawiki.page/mediawiki.page.patrol.ajax.js
new file mode 100644 (file)
index 0000000..d7a07d7
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * Animate patrol links to use asynchronous API requests to
+ * patrol pages, rather than navigating to a different URI.
+ *
+ * @since 1.21
+ * @author Marius Hoch <hoo@online.de>
+ */
+( function ( mw, $ ) {
+       if ( !mw.user.tokens.exists( 'patrolToken' ) ) {
+               // Current user has no patrol right, or an old cached version of user.tokens
+               // that didn't have patrolToken yet.
+               return;
+       }
+       $( document ).ready( function () {
+               var $patrolLinks = $( '.patrollink a' );
+               $patrolLinks.on( 'click', function ( e ) {
+                       var $spinner, href, rcid, apiRequest;
+
+                       // Hide the link and create a spinner to show it inside the brackets.
+                       $spinner = $.createSpinner( {
+                               size: 'small',
+                               type: 'inline'
+                       } );
+                       $( this ).hide().after( $spinner );
+
+                       href = $( this ).attr( 'href' );
+                       rcid = mw.util.getParamValue( 'rcid', href );
+                       apiRequest = new mw.Api();
+
+                       apiRequest.post( {
+                               action: 'patrol',
+                               token: mw.user.tokens.get( 'patrolToken' ),
+                               rcid: rcid
+                       } )
+                       .done( function ( data ) {
+                               // Remove all patrollinks from the page (including any spinners inside).
+                               $patrolLinks.closest( '.patrollink' ).remove();
+                               if ( data.patrol !== undefined ) {
+                                       // Success
+                                       var title = new mw.Title( data.patrol.title );
+                                       mw.notify( mw.msg( 'markedaspatrollednotify', title.toText() ) );
+                               } else {
+                                       // This should never happen as errors should trigger fail
+                                       mw.notify( mw.msg( 'markedaspatrollederrornotify' ) );
+                               }
+                       } )
+                       .fail( function ( error ) {
+                               $spinner.remove();
+                               // Restore the patrol link. This allows the user to try again
+                               // (or open it in a new window, bypassing this ajax module).
+                               $patrolLinks.show();
+                               if ( error === 'noautopatrol' ) {
+                                       // Can't patrol own
+                                       mw.notify( mw.msg( 'markedaspatrollederror-noautopatrol' ) );
+                               } else {
+                                       mw.notify( mw.msg( 'markedaspatrollederrornotify' ) );
+                               }
+                       } );
+
+                       e.preventDefault();
+               } );
+       } );
+}( mediaWiki, jQuery ) );