r54290 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r54289‎ | r54290 | r54291 >
Date:17:04, 3 August 2009
Author:mrzman
Status:deferred
Tags:
Comment:
Add a form to the special page to do prefix searches on page titles and the indexes table
Modified paths:
  • /trunk/extensions/IndexFunction/IndexAbstracts.php (modified) (history)
  • /trunk/extensions/IndexFunction/IndexFunction.i18n.php (modified) (history)
  • /trunk/extensions/IndexFunction/IndexFunction.php (modified) (history)
  • /trunk/extensions/IndexFunction/SpecialIndex.php (modified) (history)
  • /trunk/extensions/IndexFunction/specialindex.js (added) (history)

Diff [purge]

Index: trunk/extensions/IndexFunction/IndexFunction.i18n.php
@@ -20,13 +20,20 @@
2121 $2
2222 Please remove "$1" from the <nowiki>{{#index:}}</nowiki> on the above {{PLURAL:$3|page|pages}}.',
2323
 24+ 'index' => 'Index search',
2425 'index-legend' => 'Search the index',
2526 'index-search' => 'Search:',
2627 'index-submit' => 'Submit',
2728 'index-disambig-start' => "'''$1''' may refer to several pages:",
2829 'index-exclude-categories' => '', # List of categories to exclude from the auto-disambig pages
29 - 'index-missing-param' => 'This page cannot be used with no parameters',
3030 'index-emptylist' => 'There are no pages associated with "$1"',
 31+ 'index-expand-detail' => 'Show pages indexed under this title',
 32+ 'index-hide-detail' => 'Hide the list of pages',
 33+ 'index-no-results' => 'The search returned no results',
 34+ 'index-search-explain' => 'This page uses an prefix search.
 35+
 36+Type the first few characters and press the submit button to search for page titles and index entries that start with the search string',
 37+ 'index-details-explain' => 'Entries with arrows are index entries, click the arrow to show all pages indexed under that title.',
3138 );
3239
3340 /** Message documentation (Message documentation)
Index: trunk/extensions/IndexFunction/IndexFunction.php
@@ -30,19 +30,25 @@
3131 $wgHooks['EditPage::showEditForm:initial'][] = 'IndexFunctionHooks::editWarning';
3232 # Show a warning after page move, and do some cleanup
3333 $wgHooks['SpecialMovepageAfterMove'][] = 'IndexFunctionHooks::afterMove';
34 -
 34+# Load some Javascript for the special page
 35+$wgHooks['BeforePageDisplay'][] = 'efIndexJS';
 36+# Schema updates for update.php
3537 $wgHooks['LoadExtensionSchemaUpdates'][] = 'efIndexUpdateSchema';
3638
3739 # Setup the special page
3840 $wgSpecialPages['Index'] = 'SpecialIndex';
3941 $wgSpecialPageGroups['Index'] = 'pages';
 42+
 43+# i18n
4044 $wgExtensionAliasesFiles['IndexFunction'] = $dir . 'IndexFunction.alias.php';
 45+$wgExtensionMessagesFiles['IndexFunction'] = $dir . 'IndexFunction.i18n.php';
 46+
 47+# Register classes with the autoloader
4148 $wgAutoloadClasses['SpecialIndex'] = $dir . 'SpecialIndex.php';
42 -
43 -$wgExtensionMessagesFiles['IndexFunction'] = $dir . 'IndexFunction.i18n.php';
4449 $wgAutoloadClasses['IndexFunctionHooks'] = $dir . 'IndexFunction_body.php';
4550 $wgAutoloadClasses['IndexFunction'] = $dir . 'IndexFunction_body.php';
4651 $wgAutoloadClasses['IndexAbstracts'] = $dir . 'IndexAbstracts.php';
 52+$wgAutoloadClasses['SpecialIndexPager'] = $dir . 'SpecialIndex.php';
4753
4854 /*
4955 * Used to set the context given on Special:Index auto-disambig pages
@@ -65,3 +71,16 @@
6672 return true;
6773 }
6874
 75+function efIndexJS( &$out, &$sk ) {
 76+ $t = $out->getTitle();
 77+ if ( $t->getPrefixedText() == SpecialPage::getTitleFor( 'Index' )->getPrefixedText() ) {
 78+ global $wgScriptPath;
 79+ $tag = Xml::element( 'script',
 80+ array( 'type'=>'text/javascript', 'src'=>"$wgScriptPath/extensions/IndexFunction/specialindex.js" ),
 81+ '', false
 82+ );
 83+ $out->addScript( $tag );
 84+ }
 85+ return true;
 86+}
 87+
Index: trunk/extensions/IndexFunction/specialindex.js
@@ -0,0 +1,35 @@
 2+// Javascript for Special:Index to hide/show details
 3+// Adapted from the enhanced RC JS
 4+
 5+appendCSS('.mw-index-hidden {'+
 6+ ' display:none;'+
 7+ '}'+
 8+ 'ul.mw-index-expanded {'+
 9+ ' display:block;'+
 10+ '}'+
 11+ 'span.mw-index-expanded {'+
 12+ ' display:inline !important;'+
 13+ ' visibility:visible !important;'+
 14+ '}'+
 15+ '#use-js-note {'+
 16+ ' display: block !important;'+
 17+ '}'
 18+);
 19+
 20+/*
 21+ * Switch details between hidden/shown
 22+*/
 23+function toggleVisibility(idNumber) {
 24+ var openarrow = document.getElementById("mw-index-open-"+idNumber);
 25+ var closearrow = document.getElementById("mw-index-close-"+idNumber);
 26+ var inner = document.getElementById("mw-index-inner-"+idNumber);
 27+ if (openarrow.className == 'mw-index-expanded') {
 28+ openarrow.className = 'mw-index-hidden';
 29+ closearrow.className = 'mw-index-expanded';
 30+ inner.className = 'mw-index-expanded';
 31+ } else {
 32+ openarrow.className = 'mw-index-expanded';
 33+ closearrow.className = 'mw-index-hidden';
 34+ inner.className = 'mw-index-hidden';
 35+ }
 36+}
Property changes on: trunk/extensions/IndexFunction/specialindex.js
___________________________________________________________________
Name: svn:eol-style
137 + native
Property changes on: trunk/extensions/IndexFunction/IndexAbstracts.php
___________________________________________________________________
Name: svn:eol-style
238 + native
Index: trunk/extensions/IndexFunction/SpecialIndex.php
@@ -1,37 +1,201 @@
22 <?php
33
4 -class SpecialIndex extends UnlistedSpecialPage {
 4+class SpecialIndexPager extends AlphabeticPager {
 5+
 6+ public $mSearchTitle;
 7+ private $mJSid = 0;
 8+
 9+ function __construct( $search ) {
 10+ $this->mSearchTitle = $search;
 11+ parent::__construct();
 12+ // This can potentially be a lot of data, set a lower max limit
 13+ $this->mLimit = $this->mLimit > 1000 ? 1000 : $this->mLimit;
 14+ }
 15+
 16+ function formatRow( $row ) {
 17+ $sk = $this->getSkin();
 18+ if ( $row->type == 'page' ) {
 19+ $title = Title::makeTitle( $row->ns, $row->title );
 20+ $ret = Xml::openElement( 'tr' );
 21+ $link = $sk->link( $title, null, array(), array(), array( 'known', 'noclasses' ) );
 22+ $blankarr = $this->arrow( '' ) . '&nbsp;';
 23+ $ret .= Xml::tags( 'td', null, $blankarr );
 24+ $ret .= Xml::tags( 'td', null, $link );
 25+ $ret .= Xml::tags( 'td', null, '&nbsp;' );
 26+ $ret .= Xml::closeElement( 'tr' );
 27+ return $ret;
 28+ } else {
 29+ $ret = Xml::openElement( 'tr' );
 30+ $title = SpecialPage::getTitleFor( 'Index', $row->title );
 31+ $link = $sk->link( $title, $row->title, array( 'class'=>'mw-index' ), array(), array( 'known', 'noclasses' ) );
 32+
 33+ $jsid = $this->mJSid;
 34+ $expandTitle = wfMsgHtml( 'index-expand-detail' );
 35+ $closeTitle = wfMsgHtml( 'index-hide-detail' );
 36+ $toggleLink = "onclick='toggleVisibility($jsid); return false'";
 37+ $tl = "<span id='mw-index-open-$jsid' class='mw-index-expanded' style='visibility:hidden' ><a href='#' $toggleLink title='$expandTitle'>" . $this->sideArrow() . "</a></span>";
 38+ $tl .= "<span id='mw-index-close-$jsid' class='mw-index-hidden' style='display:none'><a href='#' $toggleLink title='$closeTitle'>" . $this->downArrow() . "</a></span>";
 39+
 40+ $ret .= Xml::tags( 'td', array( 'style' => 'vertical-align:top' ), $tl . '&nbsp' );
 41+ $ret .= Xml::tags( 'td', array( 'style' => 'vertical-align:top' ), $link );
 42+ $ret .= Xml::openElement( 'td' );
 43+ $ret .= Xml::openElement( 'ul',
 44+ array( 'style' => 'margin-top:1em', 'class'=>'mw-index-hidden', 'id'=>"mw-index-inner-$jsid" )
 45+ );
 46+ $pages = explode( '|', $row->extra );
 47+ foreach( $pages as $page ) {
 48+ $bits = explode( ':', $page, 2 );
 49+ $t = Title::makeTitle( $bits[0], $bits[1] );
 50+ $ln = $sk->link( $t, null, array(), array(), array( 'known', 'noclasses' ) );
 51+ $ret .= Xml::tags( 'li', null, $ln );
 52+ }
 53+ $ret .= Xml::closeElement( 'ul' );
 54+ $ret .= Xml::closeElement( 'td' );
 55+ $ret .= Xml::closeElement( 'tr' );
 56+ $this->mJSid++;
 57+ return $ret;
 58+ }
 59+ }
 60+
 61+ protected function arrow( $dir, $alt='', $title='' ) {
 62+ global $wgStylePath;
 63+ $encUrl = htmlspecialchars( $wgStylePath . '/common/images/Arr_' . $dir . '.png' );
 64+ $encAlt = htmlspecialchars( $alt );
 65+ $encTitle = htmlspecialchars( $title );
 66+ return "<img src=\"$encUrl\" width=\"12\" height=\"12\" alt=\"$encAlt\" title=\"$encTitle\" />";
 67+ }
 68+
 69+ protected function sideArrow() {
 70+ global $wgContLang;
 71+ $dir = $wgContLang->isRTL() ? 'l' : 'r';
 72+ return $this->arrow( $dir, '+', wfMsg( 'index-expand-detail' ) );
 73+ }
 74+
 75+ protected function downArrow() {
 76+ return $this->arrow( 'd', '-', wfMsg( 'index-hide-detail' ) );
 77+ }
 78+
 79+ protected function spacerArrow() {
 80+ return $this->arrow( '', codepointToUtf8( 0xa0 ) ); // non-breaking space
 81+ }
 82+
 83+
 84+
 85+ // Since we're overriding reallyDoQuery, we don't really need this
 86+ // its easier to just do it all in one function
 87+ function getQueryInfo() { }
 88+
 89+ function getIndexField() {
 90+ return 'title';
 91+ }
 92+
 93+ function getEmptyBody() {
 94+ return "<tr><td class='errorbox'>" . wfMsgHtml( 'index-no-results' ) ."</td></tr>";
 95+ }
 96+
 97+ // Need to override reallyDoQuery() to do the UNION
 98+ function reallyDoQuery( $offset, $limit, $descending ) {
 99+ $limit = ' LIMIT ' . intval( $limit );
 100+ $order = " ORDER BY {$this->mIndexField}";
 101+ if ( $descending ) {
 102+ $operator = '>';
 103+ } else {
 104+ $order .= ' DESC';
 105+ $operator = '<';
 106+ }
 107+
 108+ $pageconds = array();
 109+ $indexconds = array();
 110+ if ( $offset != '' ) {
 111+ $pageconds[] = 'page_title' . $operator . $this->mDb->addQuotes( $offset );
 112+ $indexconds[] = 'in_title' . $operator . $this->mDb->addQuotes( $offset );
 113+ }
 114+ $ns = $this->mSearchTitle->getNamespace();
 115+ $like = $this->mDb->escapeLike( $this->mSearchTitle->getDBkey() ) . '%';
 116+
 117+ $pageconds[] = "page_namespace = $ns";
 118+ $pageconds[] = "page_title LIKE '$like'";
 119+ $indexconds[] = "in_namespace = $ns";
 120+ $indexconds[] = "in_title LIKE '$like'";
 121+
 122+
 123+ $pagequery = $this->mDb->selectSQLText( 'page',
 124+ "page_title AS title, page_namespace AS ns, 'page' AS type, NULL AS extra",
 125+ $pageconds,
 126+ ''
 127+ );
 128+ $indexquery = $this->mDb->selectSQLText( array('indexes', 'page'),
 129+ "in_title AS title, in_namespace AS ns, 'index' AS type,
 130+ GROUP_CONCAT(page_namespace,':',page_title SEPARATOR '|') AS extra",
 131+ $indexconds,
 132+ '',
 133+ array( 'GROUP BY' => 'in_namespace, in_title' ),
 134+ array( 'page' => array('JOIN','page_id=in_from') )
 135+ );
 136+
 137+ $union = $this->mDb->unionQueries( array( $pagequery, $indexquery ), false );
 138+ $union .= $order . $limit;
 139+
 140+ $res = $this->mDb->query( $union, __METHOD__ );
 141+ return new ResultWrapper( $this->mDb, $res );
 142+ }
 143+
 144+}
 145+
 146+class SpecialIndex extends SpecialPage {
5147 function __construct() {
 148+ wfLoadExtensionMessages('IndexFunction');
6149 parent::__construct( 'Index' );
7 - wfLoadExtensionMessages('IndexFunction');
8150 }
9151
10 - function execute( $par ) {
11 - global $wgOut;
 152+ function execute( $par ) {
12153
13154 $this->setHeaders();
14155 if ($par) {
15156 $t1 = Title::newFromText( $par );
16157 $this->showDabPage( $t1 );
17 - } else {
18 - $wgOut->addWikiMsg( 'index-missing-param' );
 158+ } else {
 159+ $this->showSearchForm();
19160 }
20 - # Will eventually be some sort of a search form
21 -
22 - //$form = Xml::openElement( 'fieldset' ) .
23 - // Xml::element( 'legend', array(), wfMsgHtml( 'index-legend' ) ) .
24 - // Xml::openElement( 'form', array( 'method'=>'GET' ) ) .
25161
26 - // Xml::label( wfMsg( 'index-search' ), 'mw-index-searchtext' ) .
27 - // Xml::input( 'searchtext', 100, false, array( 'id' => 'mw-index-searchtext' ) ) .
28 - // '<br />' .
29 - // Xml::submitButton( wfMsg( 'index-submit' ) ) .
 162+ }
30163
31 - // Xml::closeElement( 'form' ) .
32 - // Xml::closeElement( 'fieldset' );
 164+ function showSearchForm() {
 165+ global $wgOut, $wgRequest, $wgScript;
 166+ $search = $wgRequest->getText( 'searchtext' );
 167+ $wgOut->addWikiMsg( 'index-search-explain' );
 168+ $form = Xml::openElement( 'fieldset', array( 'style'=>'line-height:200%' ) ) .
 169+ Xml::element( 'legend', array(), wfMsgHtml( 'index-legend' ) ) .
 170+ Xml::openElement( 'form', array( 'method'=>'GET', 'action'=>$wgScript ) ) .
 171+ Xml::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) .
33172
34 - //$wgOut->addHTML( $form );
 173+ Xml::label( wfMsg( 'index-search' ), 'mw-index-searchtext' ) .
 174+ Xml::input( 'searchtext', 100, $search, array( 'id' => 'mw-index-searchtext' ) ) .
 175+ '<br />' .
 176+ Xml::submitButton( wfMsg( 'index-submit' ) ) .
35177
 178+ Xml::closeElement( 'form' ) .
 179+ Xml::closeElement( 'fieldset' );
 180+
 181+ $wgOut->addHTML( $form );
 182+
 183+ $t = Title::newFromText( $search );
 184+
 185+ if ( !is_null( $t) ) {
 186+ $t = Title::newFromText( $wgRequest->getVal( 'searchtext' ) );
 187+ $pager = new SpecialIndexPager( $t );
 188+ $out = Xml::openElement( 'div', array( 'id'=>'mw-index-searchresults' ) ) .
 189+ '<div id="use-js-note" style="display:none">' . wfMsgExt( 'index-details-explain' , array( 'parse' ) ) . '</div>' .
 190+ $pager->getNavigationBar() .
 191+ Xml::openElement( 'table' ) .
 192+ $pager->getBody() .
 193+ Xml::closeElement( 'table' ) .
 194+ $pager->getNavigationBar() .
 195+ Xml::closeElement( 'div' );
 196+ $wgOut->addHtml( $out );
 197+
 198+ }
 199+
36200 }
37201
38202 function showDabPage( Title $t1 ) {

Status & tagging log