Autocomplete special pages' subpages in search suggestions
authorBartosz Dziewoński <matma.rex@gmail.com>
Thu, 12 Jun 2014 14:59:46 +0000 (16:59 +0200)
committerBartosz Dziewoński <matma.rex@gmail.com>
Thu, 12 Jun 2014 15:01:43 +0000 (17:01 +0200)
Includes basic "example" implementations for:
* Special:Watchlist (predefined subpage list)
* Special:Log (based on config variable)

Bug: 20210
Change-Id: I2b0505df244b9d23bd23d5fb4d3405dc28d57739

RELEASE-NOTES-1.24
includes/PrefixSearch.php
includes/specialpage/SpecialPage.php
includes/specials/SpecialLog.php
includes/specials/SpecialWatchlist.php

index 54e78ac..746e0c7 100644 (file)
@@ -64,6 +64,9 @@ production.
   that won't deplete openssl's entropy pool.
 * ResourceLoader: File modules can now provide a skip function that uses an
   inline feature test to bypass loading of the module.
+* (bug 20210) Special pages may now provide autocompletion of their subpage
+  names in search suggestions. Right now the only useful implementation is in
+  Special:Log, but more are to come.
 
 === Bug fixes in 1.24 ===
 * (bug 49116) Footer copyright notice is now always displayed in user language
index a796d35..13696ad 100644 (file)
@@ -166,10 +166,26 @@ abstract class PrefixSearch {
        protected function specialSearch( $search, $limit ) {
                global $wgContLang;
 
-               # normalize searchKey, so aliases with spaces can be found - bug 25675
-               $search = str_replace( ' ', '_', $search );
+               list( $searchKey, $subpageSearch ) = explode( '/', $search, 2 );
+
+               // Handle subpage search separately.
+               if ( $subpageSearch !== null ) {
+                       // Try matching the full search string as a page name
+                       $specialTitle = Title::makeTitleSafe( NS_SPECIAL, $searchKey );
+                       $special = SpecialPageFactory::getPage( $specialTitle->getText() );
+                       if ( $special ) {
+                               $subpages = $special->prefixSearchSubpages( $subpageSearch, $limit );
+                               return array_map( function ( $sub ) use ( $specialTitle ) {
+                                       return $specialTitle->getSubpage( $sub );
+                               }, $subpages );
+                       } else {
+                               return array();
+                       }
+               }
 
-               $searchKey = $wgContLang->caseFold( $search );
+               # normalize searchKey, so aliases with spaces can be found - bug 25675
+               $searchKey = str_replace( ' ', '_', $searchKey );
+               $searchKey = $wgContLang->caseFold( $searchKey );
 
                // Unlike SpecialPage itself, we want the canonical forms of both
                // canonical and alias title forms...
index 3968187..da51a33 100644 (file)
@@ -329,6 +329,25 @@ class SpecialPage {
                }
        }
 
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * For example, if a page supports subpages "foo", "bar" and "baz" (as in Special:PageName/foo,
+        * etc.):
+        *
+        *   - `prefixSearchSubpages( "ba" )` should return `array( "bar", "baz" )`
+        *   - `prefixSearchSubpages( "f" )` should return `array( "foo" )`
+        *   - `prefixSearchSubpages( "z" )` should return `array()`
+        *   - `prefixSearchSubpages( "" )` should return `array( foo", "bar", "baz" )`
+        *
+        * @param string $search Prefix to search for
+        * @param integer $limit Maximum number of results to return
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit = 10 ) {
+               return array();
+       }
+
        /**
         * Sets headers - this should be called from the execute() method of all derived classes!
         */
index 6da6674..aaa55a3 100644 (file)
@@ -115,6 +115,22 @@ class SpecialLog extends SpecialPage {
                $this->show( $opts, $qc );
        }
 
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param integer $limit Maximum number of results to return
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit = 10 ) {
+               global $wgLogTypes;
+               $subpages = $wgLogTypes;
+               $subpages[] = 'all';
+               sort( $subpages );
+               $escaped = preg_quote( $search );
+               return array_slice( preg_grep( "/^$escaped/i", $subpages ), 0, $limit );
+       }
+
        private function parseParams( FormOptions $opts, $par ) {
                global $wgLogTypes;
 
index 490e81f..1add311 100644 (file)
@@ -79,6 +79,19 @@ class SpecialWatchlist extends ChangesListSpecialPage {
                parent::execute( $subpage );
        }
 
+       /**
+        * Return an array of subpages beginning with $search that this special page will accept.
+        *
+        * @param string $search Prefix to search for
+        * @param integer $limit Maximum number of results to return
+        * @return string[] Matching subpages
+        */
+       public function prefixSearchSubpages( $search, $limit = 10 ) {
+               $subpages = array( 'edit', 'raw' );
+               $escaped = preg_quote( $search );
+               return array_slice( preg_grep( "/^$escaped/i", $subpages ), 0, $limit );
+       }
+
        /**
         * Get a FormOptions object containing the default options
         *