Merge "AJAXify watchlist editor"
authorCatrope <roan.kattouw@gmail.com>
Wed, 1 Aug 2012 00:24:46 +0000 (00:24 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 1 Aug 2012 00:24:46 +0000 (00:24 +0000)
includes/api/ApiWatch.php
includes/specials/SpecialEditWatchlist.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc
resources/Resources.php
resources/mediawiki.special/mediawiki.special.editWatchlist.js [new file with mode: 0644]

index 0509f1f..f307f9a 100644 (file)
@@ -40,14 +40,27 @@ class ApiWatch extends ApiBase {
                if ( !$user->isLoggedIn() ) {
                        $this->dieUsage( 'You must be logged-in to have a watchlist', 'notloggedin' );
                }
-
                $params = $this->extractRequestParams();
-               $title = Title::newFromText( $params['title'] );
-
-               if ( !$title || $title->getNamespace() < 0 ) {
-                       $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+               // titles can handle basic request of 1 title,
+               // but title is still supported for backward compatability
+               if ( isset( $params['title'] ) ) {
+                       $title = Title::newFromText( $params['title'] );
+                       if ( !$title || $title->getNamespace() < 0 ) {
+                               $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+                       }
+                       $res = $this->watchTitle( $title, $user, $params);
+               } else {
+                       $pageSet = new ApiPageSet( $this );
+                       $pageSet->execute();
+                       $res = array();
+                       foreach ( $pageSet->getTitles() as $title ) {
+                               $r = $this->watchTitle( $title, $user, $params);
+                               $res[] = $r;
+                       }
                }
-
+               $this->getResult()->addValue( null, $this->getModuleName(), $res );
+       }
+       private function watchTitle( $title, $user, $params ) {
                $res = array( 'title' => $title->getPrefixedText() );
 
                if ( $params['unwatch'] ) {
@@ -62,7 +75,7 @@ class ApiWatch extends ApiBase {
                if ( !$success ) {
                        $this->dieUsageMsg( 'hookaborted' );
                }
-               $this->getResult()->addValue( null, $this->getModuleName(), $res );
+               return $res;
        }
 
        public function mustBePosted() {
@@ -85,7 +98,10 @@ class ApiWatch extends ApiBase {
                return array(
                        'title' => array(
                                ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => true
+                       ),
+                       'titles' => array(
+                               ApiBase::PARAM_TYPE => 'string',
+                               ApiBase::PARAM_ISMULTI => true
                        ),
                        'unwatch' => false,
                        'token' => array(
index 091f5ca..21aac6f 100644 (file)
@@ -43,6 +43,8 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        const EDIT_RAW = 2;
        const EDIT_NORMAL = 3;
 
+       protected $offset = 0;
+       protected $limit = 0;
        protected $successMessage;
 
        protected $toc;
@@ -92,6 +94,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                        }
                }
                $mode = self::getMode( $this->getRequest(), $mode );
+               list( $this->limit, $this->offset ) = $this->getRequest()->getLimitOffset( 50, 'wllimit' );
 
                switch( $mode ) {
                        case self::EDIT_CLEAR:
@@ -110,6 +113,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                        case self::EDIT_NORMAL:
                        default:
                                $out->setPageTitle( $this->msg( 'watchlistedit-normal-title' ) );
+                               $out->addModules( 'mediawiki.special.editWatchlist' );
                                $form = $this->getNormalForm();
                                if( $form->show() ){
                                        $out->addHTML( $this->successMessage );
@@ -278,29 +282,42 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        }
 
        /**
-        * Get a list of titles on a user's watchlist, excluding talk pages,
-        * and return as a two-dimensional array with namespace and title.
-        *
-        * @return array
-        */
-       private function getWatchlistInfo() {
-               $titles = array();
+       * select from DB  watchlist items watched by the current user
+       * @return q query result of watchlist items watched by the current user
+       */
+       private function selectWatchListInfo( ) {
+               $options = array(
+                       'ORDER BY' => array( 'wl_namespace', 'wl_title' ),
+                       'LIMIT' => intval( $this->limit ),
+                       'OFFSET' => intval( $this->offset )
+               );
                $dbr = wfGetDB( DB_MASTER );
-
+               //query only non talk namespaces.
+               $nonTalkNamespaces = MWNamespace::getContentNamespaces();
                $res = $dbr->select(
                        array( 'watchlist' ),
                        array( 'wl_namespace',  'wl_title' ),
-                       array( 'wl_user' => $this->getUser()->getId() ),
+                       array( 'wl_user' => $this->getUser()->getId(), 'wl_namespace' => $nonTalkNamespaces  ),
                        __METHOD__,
-                       array( 'ORDER BY' => array( 'wl_namespace', 'wl_title' ) )
+                       $options
                );
 
+               return $res;
+       }
+
+       /**
+        * Get a list of titles on a user's watchlist, excluding talk pages,
+        * and return as a two-dimensional array with namespace and title.
+        *
+        * @param $watchedItems rows of watched items
+        * @return array
+        */
+       private function getWatchlistInfo( $watchedItems ) {
+               $titles = array();
                $lb = new LinkBatch();
-               foreach ( $res as $row ) {
+               foreach ( $watchedItems as $row ) {
                        $lb->add( $row->wl_namespace, $row->wl_title );
-                       if ( !MWNamespace::isTalk( $row->wl_namespace ) ) {
-                               $titles[$row->wl_namespace][$row->wl_title] = 1;
-                       }
+                       $titles[$row->wl_namespace][$row->wl_title] = 1;
                }
 
                $lb->execute();
@@ -475,8 +492,9 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                $fields = array();
                $count = 0;
-
-               foreach( $this->getWatchlistInfo() as $namespace => $pages ){
+               $watchedItems = $this->selectWatchListInfo();
+               $rowNum = $watchedItems->numRows();
+               foreach ( $this->getWatchlistInfo( $watchedItems ) as $namespace => $pages ) {
                        if ( $namespace >= 0 ) {
                                $fields['TitlesNs'.$namespace] = array(
                                        'class' => 'EditWatchlistCheckboxSeriesField',
@@ -485,7 +503,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                                );
                        }
 
-                       foreach( array_keys( $pages ) as $dbkey ){
+                       foreach ( array_keys( $pages ) as $dbkey ) {
                                $title = Title::makeTitleSafe( $namespace, $dbkey );
                                if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
                                        $text = $this->buildRemoveLine( $title );
@@ -518,10 +536,13 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
                $form = new EditWatchlistNormalHTMLForm( $fields, $this->getContext() );
                $form->setTitle( $this->getTitle() );
                $form->setSubmitTextMsg( 'watchlistedit-normal-submit' );
+               $form->setSubmitID( 'watchlistedit-submit' );
                # Used message keys: 'accesskey-watchlistedit-normal-submit', 'tooltip-watchlistedit-normal-submit'
                $form->setSubmitTooltip('watchlistedit-normal-submit');
                $form->setWrapperLegendMsg( 'watchlistedit-normal-legend' );
-               $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() );
+               $paging = '<p>' . $this->getLanguage()->viewPrevNext( $this->getTitle(), $this->offset,
+                               $this->limit,  array(), ( $rowNum < $this->limit ) ) . '</p>';
+               $form->addHeaderText( $this->msg( 'watchlistedit-normal-explain' )->parse() . $paging );
                $form->setSubmitCallback( array( $this, 'submitNormal' ) );
                return $form;
        }
@@ -556,7 +577,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
                wfRunHooks( 'WatchlistEditorBuildRemoveLine', array( &$tools, $title, $title->isRedirect(), $this->getSkin() ) );
 
-               return $link . " (" . $this->getLanguage()->pipeList( $tools ) . ")";
+               return '<span class="watchlist-item">' . $link . '</span>' . " (" . $this->getLanguage()->pipeList( $tools ) . ")";
        }
 
        /**
index ec67281..c8c38e7 100644 (file)
@@ -4538,6 +4538,7 @@ Try normal preview.',
 To remove a title, check the box next to it, and click "{{int:Watchlistedit-normal-submit}}".
 You can also [[Special:EditWatchlist/raw|edit the raw list]].',
 'watchlistedit-normal-submit'  => 'Remove titles',
+'watchlistedit-normal-submitting'  => 'Removing titles...',
 'watchlistedit-normal-done'    => '{{PLURAL:$1|1 title was|$1 titles were}} removed from your watchlist:',
 'watchlistedit-raw-title'      => 'Edit raw watchlist',
 'watchlistedit-raw-legend'     => 'Edit raw watchlist',
index c5a511a..0376bc9 100644 (file)
@@ -4335,6 +4335,7 @@ Bitrate (of a file, typically) in yottabits (1 yottabits = 1000×1000×1000×100
 Hint: the text "Remove Titles" is in {{msg-mw|watchlistedit-normal-submit}}',
 'watchlistedit-normal-submit' => 'Text of submit button on [[Special:Watchlist/edit]].',
 'watchlistedit-normal-done' => 'Message on [[Special:EditWatchlist]] after pages are removed from the watchlist.',
+'watchlistedit-normal-submitting' => 'Text of submit button on [[Special:Watchlist/edit]] when submiting an AJAX request',
 'watchlistedit-raw-title' => 'Title of [[Special:Watchlist/raw|Special page]].
 
 {{Identical|Edit raw watchlist}}',
index 126faaa..af06423 100644 (file)
@@ -3404,6 +3404,7 @@ $wgMessageStructure = array(
                'watchlistedit-normal-legend',
                'watchlistedit-normal-explain',
                'watchlistedit-normal-submit',
+               'watchlistedit-normal-submiting',
                'watchlistedit-normal-done',
                'watchlistedit-raw-title',
                'watchlistedit-raw-legend',
index 337367f..1d3c62a 100644 (file)
@@ -804,6 +804,14 @@ return array(
                'styles' => 'resources/mediawiki.special/mediawiki.special.changeslist.css',
                'dependencies' => array( 'jquery.makeCollapsible' ),
        ),
+       'mediawiki.special.editWatchlist' => array(
+               'scripts' => 'resources/mediawiki.special/mediawiki.special.editWatchlist.js',
+               'dependencies' => array(
+                       'mediawiki.api',
+                       'user.tokens'
+               ),
+               'messages' => array( 'watchlistedit-normal-submit', 'watchlistedit-normal-submiting' )
+       ),
        'mediawiki.special.movePage' => array(
                'scripts' => 'resources/mediawiki.special/mediawiki.special.movePage.js',
                'dependencies' => 'jquery.byteLimit',
diff --git a/resources/mediawiki.special/mediawiki.special.editWatchlist.js b/resources/mediawiki.special/mediawiki.special.editWatchlist.js
new file mode 100644 (file)
index 0000000..66329cf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * JavaScript for Special:EditWatchlist
+ */
+
+/**
+ * Replace the submit button action to operate with ajax.
+ */
+( function ( mw, $ ) {
+       $( '#watchlistedit-submit' ).parents( 'form:first' ).on( 'submit.ajax', function ( e ) {
+               var titlesToRemove, params, api;
+               titlesToRemove = $.map( $( '.mw-htmlform-flatlist-item input:checked' ), function ( el ) {
+                       return $( el ).val();
+               } ).join( '|' );
+               params = {
+                       action: 'watch',
+                       titles: titlesToRemove,
+                       token: mw.user.tokens.get( 'watchToken' ),
+                       unwatch: '1'
+               };
+               api = new mw.Api();
+               api.ajax( params, { type: 'POST' } ).done( function ( data ) {
+                               $.each( data.watch, function ( e ) {
+                                       var removedItem = this.title;
+                                       var item = $( '.watchlist-item a' ).filter( function ( ) {
+                                                               return this.title === removedItem;
+                                                       } ).parents( '.mw-htmlform-flatlist-item' ).fadeOut();
+                               } );
+                               $( '#watchlistedit-submit' ).prop( {
+                                       disabled: false,
+                                       value: mw.msg( 'watchlistedit-normal-submit' )
+                               } );
+                       } ).fail( function () {
+                               //some error occurred.
+                               //re-enable the submit and try to send normal submit
+                               $( '#watchlistedit-submit' ).prop( {
+                                       disabled: false,
+                                       value: mw.msg( 'watchlistedit-normal-submit' )
+                               } ).parents( 'form:first' )
+                                  .off( 'submit.ajax' ).submit();
+                       } );
+               $( '#watchlistedit-submit' ).prop( { disabled: true, value:  mw.msg( 'watchlistedit-normal-submitting' )  } );
+               e.preventDefault();
+       } );
+} )( mediaWiki, jQuery );