return null;
}
+ /** If this search backend can list/unlist redirects */
+ function acceptListRedirects() {
+ return true;
+ }
+
/**
* If an exact title match can be find, or a very slightly close match,
* return the title. If no match, returns NULL.
*/
public static function userNamespaces( &$user ) {
$arr = array();
+ // for logged-in users use predefined defaults
+ if( $user->isLoggedIn() && $user->getOption( 'defaultusersearch', true ) )
+ return SearchEngine::projectNamespaces();
+
foreach( SearchEngine::searchableNamespaces() as $ns => $name ) {
if( $user->getOption( 'searchNs' . $ns ) ) {
$arr[] = $ns;
return array_keys($wgNamespacesToBeSearchedDefault, true);
}
-
+
+ /**
+ * Get a list of namespace names useful for showing in tooltips
+ * and preferences
+ *
+ * @param unknown_type $namespaces
+ */
+ public static function namespacesAsText( $namespaces ){
+ global $wgContLang;
+
+ $formatted = array_map( array($wgContLang,'getFormattedNsText'), $namespaces );
+ foreach( $formatted as $key => $ns ){
+ if ( empty($ns) )
+ $formatted[$key] = wfMsg( 'blanknamespace' );
+ }
+ return $formatted;
+ }
+
+ /**
+ * An array of "project" namespaces indexes typically searched
+ * by logged-in users
+ *
+ * @return array
+ * @static
+ */
+ public static function projectNamespaces(){
+ global $wgNamespacesToBeSearchedDefault, $wgNamespacesToBeSearchedProject;
+
+ return array_keys( $wgNamespacesToBeSearchedDefault +
+ $wgNamespacesToBeSearchedProject, true);
+ }
+
/**
* Return a 'cleaned up' search string
*
else
return $wgServer . $wgScriptPath . '/api.php?action=opensearch&search={searchTerms}&namespace={namespaces}';
}
+
}
/**
*/
class SearchResult {
var $mRevision = null;
+ var $mImage = null;
function SearchResult( $row ) {
$this->mTitle = Title::makeTitle( $row->page_namespace, $row->page_title );
- if( !is_null($this->mTitle) )
+ if( !is_null($this->mTitle) ){
$this->mRevision = Revision::newFromTitle( $this->mTitle );
+ if($this->mTitle->getNamespace() == NS_IMAGE)
+ $this->mImage = wfFindFile( $this->mTitle );
+ }
+
+
}
/**
* @access public
*/
function isMissingRevision(){
- if( !$this->mRevision )
+ if( !$this->mRevision && !$this->mImage )
return true;
return false;
}
*/
protected function initText(){
if( !isset($this->mText) ){
- $this->mText = $this->mRevision->getText();
+ if($this->mRevision != null)
+ $this->mText = $this->mRevision->getText();
+ else
+ $this->mText = '';
}
}
* @return string timestamp
*/
function getTimestamp(){
- return $this->mRevision->getTimestamp();
+ if($this->mRevision != null)
+ return $this->mRevision->getTimestamp();
+ else
+ return '';
}
/**
$this->mWatchlistDays = $request->getVal( 'wpWatchlistDays' );
$this->mWatchlistEdits = $request->getVal( 'wpWatchlistEdits' );
$this->mDisableMWSuggest = $request->getCheck( 'wpDisableMWSuggest' );
+ $this->mDefaultUserSearch = $request->getVal( 'wpUserSearch' ) != 'wpCustomUserSearch';
$this->mSaveprefs = $request->getCheck( 'wpSaveprefs' ) &&
$this->mPosted &&
$wgUser->setOption( 'underline', $this->validateInt($this->mUnderline, 0, 2) );
$wgUser->setOption( 'watchlistdays', $this->validateFloat( $this->mWatchlistDays, 0, 7 ) );
$wgUser->setOption( 'disablesuggest', $this->mDisableMWSuggest );
+ $wgUser->setOption( 'defaultusersearch', $this->mDefaultUserSearch );
# Set search namespace options
foreach( $this->mSearchNs as $i => $value ) {
return Xml::tags( 'tr', null, $td1 . $td2 ). $td3 . "\n";
}
-
+
/**
* @access private
*/
$wgOut->addHtml( '</fieldset>' );
# Search
+ $defaultNs = SearchEngine::namespacesAsText( SearchEngine::projectNamespaces() );
$mwsuggest = $wgEnableMWSuggest ?
$this->addRow(
Xml::label( wfMsg( 'mwsuggest-disable' ), 'wpDisableMWSuggest' ),
Xml::check( 'wpDisableMWSuggest', $this->mDisableMWSuggest, array( 'id' => 'wpDisableMWSuggest' ) )
) : '';
+ $userDefaultSearch = '<p>'.Xml::radioLabel(wfMsg('prefs-search-nsdefault'),'wpUserSearch','wpDefaultUserSearch','wpDefaultUserSearch',$this->mDefaultUserSearch).
+ '</p>'.implode(', ', $defaultNs).'<br/><br/><p>'.
+ Xml::radioLabel(wfMsg('prefs-search-nscustom'),'wpUserSearch','wpCustomUserSearch','wpCustomUserSearch',!$this->mDefaultUserSearch).
+ '</p>';
$wgOut->addHTML(
// Elements for the search tab itself
Xml::openElement( 'fieldset' ) .
// Elements for the namespace options in the search tab
Xml::openElement( 'fieldset' ) .
Xml::element( 'legend', null, wfMsg( 'prefs-namespaces' ) ) .
- wfMsgExt( 'defaultns', array( 'parse' ) ) .
+ $userDefaultSearch.
$ps .
Xml::closeElement( 'fieldset' ) .
// End of the search tab
}
$this->searchRedirects = $request->getcheck( 'redirs' ) ? true : false;
+ $this->searchAdvanced = $request->getVal('advanced');
}
/**
}
}
- $wgOut->wrapWikiMsg( "==$1==\n", 'notitlematches' );
- if( $t->quickUserCan( 'create' ) && $t->quickUserCan( 'edit' ) ) {
- $wgOut->addWikiMsg( 'noexactmatch', wfEscapeWikiText( $term ) );
- } else {
- $wgOut->addWikiMsg( 'noexactmatch-nocreate', wfEscapeWikiText( $term ) );
- }
-
return $this->showResults( $term );
}
$sk = $wgUser->getSkin();
$this->setupPage( $term );
-
- $wgOut->addWikiMsg( 'searchresulttext' );
+ $this->searchEngine = SearchEngine::create();
+
+ $t = Title::newFromText( $term );
+
+ // add a table since it's difficult to stack divs horizontally nicely
+ // left - search box, right - search menu
+
+ $wgOut->addHtml(
+ Xml::openElement('table', array( 'border'=>'0' ) ).
+ Xml::openElement('tr').
+ Xml::openElement('td')
+ );
+
+
+ if( $this->searchAdvanced ){
+ $wgOut->addHTML( $this->powerSearchBox( $term ) );
+ $showMenu = false;
+ } else {
+ $wgOut->addHTML( $this->shortDialog( $term ) );
+ $showMenu = true;
+ }
+
+ $wgOut->addHtml( Xml::closeElement('div').
+ Xml::closeElement('td'));
+
+
+ $wgOut->addHtml( Xml::openElement('td', array( 'id' => 'mw-search-menu' )) );
+
+ if( $showMenu ){
+ if( $t!=null && $t->quickUserCan( 'create' ) && $t->quickUserCan( 'edit' ) ) {
+ if( $t->exists() ){
+ $wgOut->addWikiMsg( 'searchmenu-exists', wfEscapeWikiText( $term ) );
+ } else {
+ $wgOut->addWikiMsg( 'searchmenu-new', wfEscapeWikiText( $term ) );
+ }
+ }
+ }
+ $wgOut->addWikiMsg( 'searchmenu', wfEscapeWikiText( $term ) );
+
+
+ $wgOut->addHtml(
+ Xml::closeElement('td').
+ Xml::closeElement('tr').
+ Xml::closeElement('table')
+ );
+
if( '' === trim( $term ) ) {
// Empty query -- straight view of search form
- $wgOut->setSubtitle( '' );
- $wgOut->addHTML( $this->powerSearchBox( $term ) );
- $wgOut->addHTML( $this->powerSearchFocus() );
wfProfileOut( $fname );
return;
}
return;
}
- $wgOut->addHTML( $this->shortDialog( $term ) );
-
- $search = SearchEngine::create();
+ $search = $this->searchEngine;
$search->setLimitOffset( $this->limit, $this->offset );
$search->setNamespaces( $this->namespaces );
$search->showRedirects = $this->searchRedirects;
// Sometimes the search engine knows there are too many hits
if ($titleMatches instanceof SearchResultTooMany) {
$wgOut->addWikiText( '==' . wfMsg( 'toomanymatches' ) . "==\n" );
- $wgOut->addHTML( $this->powerSearchBox( $term ) );
- $wgOut->addHTML( $this->powerSearchFocus() );
wfProfileOut( $fname );
return;
}
$textMatches = $search->searchText( $rewritten );
-
+
+
// did you mean... suggestions
if($textMatches && $textMatches->hasSuggestion()){
$st = SpecialPage::getTitleFor( 'Search' );
$textMatches->getSuggestionSnippet().'</a>';
$wgOut->addHTML('<div class="searchdidyoumean">'.wfMsg('search-suggest',$suggestLink).'</div>');
- }
-
+ }
+
// show number of results
$num = ( $titleMatches ? $titleMatches->numRows() : 0 )
+ ( $textMatches ? $textMatches->numRows() : 0);
}
if ( $num == 0 ) {
- $wgOut->addWikiMsg( 'nonefound' );
+ $wgOut->addWikiMsg( 'search-nonefound' );
}
if( $num || $this->offset ) {
$wgOut->addHTML( "<p class='mw-search-pager-bottom'>{$prevnext}</p>\n" );
}
- $wgOut->addHTML( $this->powerSearchBox( $term ) );
wfProfileOut( $fname );
}
$wgOut->setPageTitle( wfMsg( 'searchresults') );
$wgOut->setHTMLTitle( wfMsg( 'pagetitle', wfMsg( 'searchresults-title', $term) ) );
}
- $subtitlemsg = ( Title::newFromText( $term ) ? 'searchsubtitle' : 'searchsubtitleinvalid' );
- $wgOut->setSubtitle( $wgOut->parse( wfMsg( $subtitlemsg, wfEscapeWikiText($term) ) ) );
$wgOut->setArticleRelated( false );
$wgOut->setRobotPolicy( 'noindex,nofollow' );
}
$opt['ns' . $n] = 1;
}
$opt['redirs'] = $this->searchRedirects ? 1 : 0;
+ if( $this->searchAdvanced )
+ $opt['advanced'] = $this->searchAdvanced;
return $opt;
}
Xml::closeElement( 'span' ) . "\n";
}
- $redirect = Xml::check( 'redirs', $this->searchRedirects, array( 'value' => '1', 'id' => 'redirs' ) );
- $redirectLabel = Xml::label( wfMsg( 'powersearch-redir' ), 'redirs' );
+ if( $this->searchEngine->acceptListRedirects() ){
+ $redirect = Xml::check( 'redirs', $this->searchRedirects, array( 'value' => '1', 'id' => 'redirs' ) );
+ $redirectLabel = Xml::label( wfMsg( 'powersearch-redir' ), 'redirs' );
+ } else{
+ $redirect = '';
+ $redirectLabel = '';
+ }
$searchField = Xml::input( 'search', 50, $term, array( 'type' => 'text', 'id' => 'powerSearchText' ) );
$searchButton = Xml::submitButton( wfMsg( 'powersearch' ), array( 'name' => 'fulltext' ) ) . "\n";
$searchTitle = SpecialPage::getTitleFor( 'Search' );
$out = Xml::openElement( 'form', array( 'id' => 'powersearch', 'method' => 'get', 'action' => $wgScript ) ) .
- Xml::fieldset( wfMsg( 'powersearch-legend' ),
Xml::hidden( 'title', $searchTitle->getPrefixedText() ) .
"<p>" .
wfMsgExt( 'powersearch-ns', array( 'parseinline' ) ) .
" " .
$searchField .
" " .
- $searchButton ) .
+ $searchButton.
"</form>";
- return $out;
+ return $this->formHeader($term).$out;
}
function powerSearchFocus() {
"});" .
"</script>";
}
+
+ /** Make a search link with some target namespaces */
+ function makeSearchLink($term, $namespaces, $label, $tooltip, $params=array()){
+ $opt = $params;
+ foreach( $namespaces as $n ) {
+ $opt['ns' . $n] = 1;
+ }
+ $opt['redirs'] = $this->searchRedirects ? 1 : 0;
+
+ $st = SpecialPage::getTitleFor( 'Search' );
+ $stParams = wfArrayToCGI( array(
+ 'search' => $term,
+ 'fulltext' => wfMsg('search')),
+ $opt);
+
+ return Xml::element('a',
+ array('href'=> $st->getLocalURL($stParams), 'title' => $tooltip),
+ $label);
+
+ }
+
+ /** Check if query starts with image: prefix */
+ function startsWithImage($term){
+ global $wgContLang;
+
+ $p = explode(':',$term);
+ if( count($p)> 1 ){
+ return $wgContLang->getNsIndex($p[0]) == NS_IMAGE;
+ }
+ return false;
+ }
+
+ /** Check if query begins with all: magic prefix */
+ function startsWithAll($term){
+ global $wgContLang;
+
+ $p = explode(':',$term);
+ return count($p) > 1 && $p[0]==wfMsg('searchall');
+ }
+ function formHeader($term) {
+ global $wgContLang;
+
+ $sep = ' ';
+ $out = Xml::openElement('div', array('style'=>'padding-bottom:0.5em;'));
+
+ $bareterm = $term;
+ if($this->startsWithAll($term) || $this->startsWithImage($term))
+ $bareterm = substr( $term, strpos($term,':')+1 ); // delete all/image prefix
+
+ // figure out the active search profile header
+ if( $this->searchAdvanced )
+ $active = 'advanced';
+ else if( $this->namespaces == NS_IMAGE || $this->startsWithImage($term) )
+ $active = 'images';
+ elseif( $this->startsWithAll($term) )
+ $active = 'all';
+ elseif( $this->namespaces == SearchEngine::defaultNamespaces() )
+ $active = 'default';
+ elseif( $this->namespaces == SearchEngine::projectNamespaces() )
+ $active = 'project';
+ else
+ $active = 'advanced';
+
+
+ // search profiles headers
+ $m = wfMsg('searchprofile-articles');
+ $tt = wfMsg('searchprofile-articles-tooltip',
+ implode(', ', SearchEngine::namespacesAsText( SearchEngine::defaultNamespaces() )));
+ if( $active == 'default' ){
+ $out .= Xml::element('strong', array('title'=>$tt), $m);
+ } else
+ $out .= $this->makeSearchLink( $bareterm, SearchEngine::defaultNamespaces(), $m, $tt );
+
+ $out .= $sep;
+
+ $m = wfMsg('searchprofile-project');
+ $tt = wfMsg('searchprofile-project-tooltip',
+ implode(', ', SearchEngine::namespacesAsText( SearchEngine::projectNamespaces() )));
+ if( $active == 'project' ){
+ $out .= Xml::element('strong', array('title'=>$tt), $m);
+ } else
+ $out .= $this->makeSearchLink( $bareterm, SearchEngine::projectNamespaces(), $m, $tt );
+
+ $out .= $sep;
+
+ $m = wfMsg('searchprofile-images');
+ $tt = wfMsg('searchprofile-images-tooltip');
+ if( $active == 'images' ){
+ $out .= Xml::element('strong', array('title'=>$tt), $m);
+ } else
+ $out .= $this->makeSearchLink( $wgContLang->getFormattedNsText(NS_IMAGE).':'.$bareterm, array() , $m, $tt );
+
+ $out .= $sep;
+
+ $m = wfMsg('searchprofile-everything');
+ $tt = wfMsg('searchprofile-everything-tooltip');
+ if( $active == 'all' ){
+ $out .= Xml::element('strong', array('title'=>$tt), $m);
+ } else
+ $out .= $this->makeSearchLink( wfMsg('searchall').':'.$bareterm, array() , $m, $tt );
+
+ $out .= $sep;
+
+ $m = wfMsg('searchprofile-advanced');
+ $tt = wfMsg('searchprofile-advanced-tooltip');
+ if( $active == 'advanced' ){
+ $out .= Xml::element('strong', array('title'=>$tt), $m);
+ } else
+ $out .= $this->makeSearchLink( $bareterm, array() , $m, $tt, array( 'advanced' => '1') );
+
+ $out .= Xml::closeElement('div') ;
+
+ return $out;
+ }
+
function shortDialog($term) {
global $wgScript;
-
- $out = Xml::openElement( 'form', array(
+
+ $out = Xml::openElement( 'form', array(
'id' => 'search',
'method' => 'get',
'action' => $wgScript
$searchTitle = SpecialPage::getTitleFor( 'Search' );
$out .= Xml::hidden( 'title', $searchTitle->getPrefixedText() );
$out .= Xml::input( 'search', 50, $term, array( 'type' => 'text', 'id' => 'searchText' ) ) . ' ';
+
foreach( SearchEngine::searchableNamespaces() as $ns => $name ) {
if( in_array( $ns, $this->namespaces ) ) {
$out .= Xml::hidden( "ns{$ns}", '1' );
$out .= Xml::submitButton( wfMsg( 'searchbutton' ), array( 'name' => 'fulltext' ) );
$out .= Xml::closeElement( 'form' );
- return $out;
+ return $this->formHeader($term).$out;
}
}
# Search results
'searchresults' => 'Search results',
'searchresults-title' => 'Search results for $1',
-'searchresulttext' => 'For more information about searching {{SITENAME}}, see [[{{MediaWiki:Helppage}}|{{int:help}}]].',
-'searchsubtitle' => 'You searched for \'\'\'[[:$1]]\'\'\' ([[Special:Prefixindex/$1|all pages starting with "$1"]] | [[Special:WhatLinksHere/$1|all pages that link to "$1"]])',
-'searchsubtitleinvalid' => "You searched for '''$1'''",
-'noexactmatch' => "'''There is no page titled \"\$1\".'''
-You can [[:\$1|create this page]].",
-'noexactmatch-nocreate' => "'''There is no page titled \"\$1\".'''",
'toomanymatches' => 'Too many matches were returned, please try a different query',
'titlematches' => 'Page title matches',
'notitlematches' => 'No page title matches',
'prevn' => 'previous $1',
'nextn' => 'next $1',
'viewprevnext' => 'View ($1) ($2) ($3)',
+'searchmenu-exists' => "*Article '''[[$1]]'''\n",
+'searchmenu-new' => "*Create article '''[[$1]]'''\n",
+'searchmenu' => "*[[Special:AllPages/$1|Index]]\n*[[{{ns:project}}:Searching|{{int:help}}]]\n",
+'searchprofile-articles' => 'Articles',
+'searchprofile-project' => 'Articles/Project',
+'searchprofile-images' => 'Images',
+'searchprofile-everything' => 'Everything',
+'searchprofile-advanced' => 'Advanced',
+'searchprofile-articles-tooltip' => 'Search in $1',
+'searchprofile-project-tooltip' => 'Search in $1',
+'searchprofile-images-tooltip' => 'Search for images',
+'searchprofile-everything-tooltip' => 'Search all of content (including talk pages)',
+'searchprofile-advanced-tooltip' => 'Search in custom namespaces',
+'prefs-search-nsdefault' => 'Search using defaults:',
+'prefs-search-nscustom' => 'Search custom namespaces:',
'search-result-size' => '$1 ({{PLURAL:$2|1 word|$2 words}})',
'search-result-score' => 'Relevance: $1%',
'search-redirect' => '(redirect $1)',
'showingresults' => "Showing below up to {{PLURAL:$1|'''1''' result|'''$1''' results}} starting with #'''$2'''.",
'showingresultsnum' => "Showing below {{PLURAL:$3|'''1''' result|'''$3''' results}} starting with #'''$2'''.",
'showingresultstotal' => "Showing below {{PLURAL:$4|result '''$1''' of '''$3'''|results '''$1 - $2''' of '''$3'''}}",
-'nonefound' => "'''Note''': Only some namespaces are searched by default.
-Try prefixing your query with ''all:'' to search all content (including talk pages, templates, etc), or use the desired namespace as prefix.",
+'search-nonefound' => "There were no results matching the query.",
'powersearch' => 'Advanced search',
'powersearch-legend' => 'Advanced search',
'powersearch-ns' => 'Search in namespaces:',
'allowemail' => 'Enable e-mail from other users',
'prefs-searchoptions' => 'Search options',
'prefs-namespaces' => 'Namespaces',
-'defaultns' => 'Search in these namespaces by default:',
'default' => 'default',
'files' => 'Files',