Index: trunk/extensions/IndexFunction/IndexFunction.i18n.php |
— | — | @@ -20,13 +20,20 @@ |
21 | 21 | $2 |
22 | 22 | Please remove "$1" from the <nowiki>{{#index:}}</nowiki> on the above {{PLURAL:$3|page|pages}}.', |
23 | 23 | |
| 24 | + 'index' => 'Index search', |
24 | 25 | 'index-legend' => 'Search the index', |
25 | 26 | 'index-search' => 'Search:', |
26 | 27 | 'index-submit' => 'Submit', |
27 | 28 | 'index-disambig-start' => "'''$1''' may refer to several pages:", |
28 | 29 | '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', |
30 | 30 | '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.', |
31 | 38 | ); |
32 | 39 | |
33 | 40 | /** Message documentation (Message documentation) |
Index: trunk/extensions/IndexFunction/IndexFunction.php |
— | — | @@ -30,19 +30,25 @@ |
31 | 31 | $wgHooks['EditPage::showEditForm:initial'][] = 'IndexFunctionHooks::editWarning'; |
32 | 32 | # Show a warning after page move, and do some cleanup |
33 | 33 | $wgHooks['SpecialMovepageAfterMove'][] = 'IndexFunctionHooks::afterMove'; |
34 | | - |
| 34 | +# Load some Javascript for the special page |
| 35 | +$wgHooks['BeforePageDisplay'][] = 'efIndexJS'; |
| 36 | +# Schema updates for update.php |
35 | 37 | $wgHooks['LoadExtensionSchemaUpdates'][] = 'efIndexUpdateSchema'; |
36 | 38 | |
37 | 39 | # Setup the special page |
38 | 40 | $wgSpecialPages['Index'] = 'SpecialIndex'; |
39 | 41 | $wgSpecialPageGroups['Index'] = 'pages'; |
| 42 | + |
| 43 | +# i18n |
40 | 44 | $wgExtensionAliasesFiles['IndexFunction'] = $dir . 'IndexFunction.alias.php'; |
| 45 | +$wgExtensionMessagesFiles['IndexFunction'] = $dir . 'IndexFunction.i18n.php'; |
| 46 | + |
| 47 | +# Register classes with the autoloader |
41 | 48 | $wgAutoloadClasses['SpecialIndex'] = $dir . 'SpecialIndex.php'; |
42 | | - |
43 | | -$wgExtensionMessagesFiles['IndexFunction'] = $dir . 'IndexFunction.i18n.php'; |
44 | 49 | $wgAutoloadClasses['IndexFunctionHooks'] = $dir . 'IndexFunction_body.php'; |
45 | 50 | $wgAutoloadClasses['IndexFunction'] = $dir . 'IndexFunction_body.php'; |
46 | 51 | $wgAutoloadClasses['IndexAbstracts'] = $dir . 'IndexAbstracts.php'; |
| 52 | +$wgAutoloadClasses['SpecialIndexPager'] = $dir . 'SpecialIndex.php'; |
47 | 53 | |
48 | 54 | /* |
49 | 55 | * Used to set the context given on Special:Index auto-disambig pages |
— | — | @@ -65,3 +71,16 @@ |
66 | 72 | return true; |
67 | 73 | } |
68 | 74 | |
| 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 |
1 | 37 | + native |
Property changes on: trunk/extensions/IndexFunction/IndexAbstracts.php |
___________________________________________________________________ |
Name: svn:eol-style |
2 | 38 | + native |
Index: trunk/extensions/IndexFunction/SpecialIndex.php |
— | — | @@ -1,37 +1,201 @@ |
2 | 2 | <?php |
3 | 3 | |
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( '' ) . ' '; |
| 23 | + $ret .= Xml::tags( 'td', null, $blankarr ); |
| 24 | + $ret .= Xml::tags( 'td', null, $link ); |
| 25 | + $ret .= Xml::tags( 'td', null, ' ' ); |
| 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 . ' ' ); |
| 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 { |
5 | 147 | function __construct() { |
| 148 | + wfLoadExtensionMessages('IndexFunction'); |
6 | 149 | parent::__construct( 'Index' ); |
7 | | - wfLoadExtensionMessages('IndexFunction'); |
8 | 150 | } |
9 | 151 | |
10 | | - function execute( $par ) { |
11 | | - global $wgOut; |
| 152 | + function execute( $par ) { |
12 | 153 | |
13 | 154 | $this->setHeaders(); |
14 | 155 | if ($par) { |
15 | 156 | $t1 = Title::newFromText( $par ); |
16 | 157 | $this->showDabPage( $t1 ); |
17 | | - } else { |
18 | | - $wgOut->addWikiMsg( 'index-missing-param' ); |
| 158 | + } else { |
| 159 | + $this->showSearchForm(); |
19 | 160 | } |
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' ) ) . |
25 | 161 | |
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 | + } |
30 | 163 | |
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() ) . |
33 | 172 | |
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' ) ) . |
35 | 177 | |
| 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 | + |
36 | 200 | } |
37 | 201 | |
38 | 202 | function showDabPage( Title $t1 ) { |