From: Robert Stojnić Date: Sun, 23 Mar 2008 13:43:11 +0000 (+0000) Subject: Search frontend: X-Git-Tag: 1.31.0-rc.0~48867 X-Git-Url: http://git.cyclocoop.org/%40spipnet%40?a=commitdiff_plain;h=82d7b2216bb4ea8eed93a79cdbcd11c812e880dc;p=lhc%2Fweb%2Fwiklou.git Search frontend: * let the backend provide snippets and other info, fill only what is not provided * wrap textual results in a div, should make the snippets look more compact and consistent over hits * added a did you mean.. container * show total number of hits if available * added messages for "redirects to article", and "relevant section" hits --- diff --git a/includes/SearchEngine.php b/includes/SearchEngine.php index ff93cdfa25..739e8a1084 100644 --- a/includes/SearchEngine.php +++ b/includes/SearchEngine.php @@ -309,13 +309,16 @@ class SearchResultSet { } /** - * Some search modes return a suggested alternate term if there are - * no exact hits. Check hasSuggestion() first. - * - * @return string - * @access public + * @return string suggested query, null if none + */ + function getSuggestionQuery(){ + return null; + } + + /** + * @return string highlighted suggested query, '' if none */ - function getSuggestion() { + function getSuggestionSnippet(){ return ''; } @@ -370,6 +373,69 @@ class SearchResult { function getScore() { return null; } + + /** + * @return string highlighted text snippet, null if not supported + */ + function getTextSnippet(){ + return null; + } + + /** + * @return string highlighted title, '' if not supported + */ + function getTitleSnippet(){ + return ''; + } + + /** + * @return string highlighted redirect name (redirect to this page), '' if none or not supported + */ + function getRedirectSnippet(){ + return ''; + } + + /** + * @return Title object for the redirect to this page, null if none or not supported + */ + function getRedirectTitle(){ + return null; + } + + /** + * @return string highlighted relevant section name, null if none or not supported + */ + function getSectionSnippet(){ + return ''; + } + + /** + * @return Title object (pagename+fragment) for the section, null if none or not supported + */ + function getSectionTitle(){ + return null; + } + + /** + * @return string timestamp, null if not supported + */ + function getTimestamp(){ + return null; + } + + /** + * @return int number of words, null if not supported + */ + function getWordCount(){ + return null; + } + + /** + * @return int size in bytes, null if not supported + */ + function getByteSize(){ + return null; + } } /** diff --git a/includes/SpecialSearch.php b/includes/SpecialSearch.php index d91445431a..434ea33a2a 100644 --- a/includes/SpecialSearch.php +++ b/includes/SpecialSearch.php @@ -171,11 +171,29 @@ class SpecialSearch { return; } $textMatches = $search->searchText( $term ); + + // did you mean... + if($textMatches && $textMatches->hasSuggestion()){ + global $wgScript; + $fulltext = htmlspecialchars(wfMsg('search')); + $suggestLink = '' + .$textMatches->getSuggestionSnippet().''; + $wgOut->addHTML('
'.wfMsg('search-suggest',$suggestLink).'
'); + } + $num = ( $titleMatches ? $titleMatches->numRows() : 0 ) + ( $textMatches ? $textMatches->numRows() : 0); + $totalNum = 0; + if($titleMatches && !is_null($titleMatches->getTotalHits())) + $totalNum += $titleMatches->getTotalHits(); + if($textMatches && !is_null($textMatches->getTotalHits())) + $totalNum += $textMatches->getTotalHits(); if ( $num > 0 ) { - if ( $num >= $this->limit ) { + if ( $totalNum > 0 ){ + $top = wfMsgExt('showingresultstotal',array( 'parseinline' ), $this->offset+1, $this->offset+$num, $totalNum); + } elseif ( $num >= $this->limit ) { $top = wfShowingResults( $this->offset, $this->limit ); } else { $top = wfShowingResultsNum( $this->offset, $this->limit, $num ); @@ -208,7 +226,10 @@ class SpecialSearch { if( $textMatches ) { if( $textMatches->numRows() ) { - $wgOut->wrapWikiMsg( "==$1==\n", 'textmatches' ); + if($titleMatches) + $wgOut->wrapWikiMsg( "==$1==\n", 'textmatches' ); + else // if no title matches the heading is redundant + $wgOut->addHTML("
"); $wgOut->addHTML( $this->showMatches( $textMatches ) ); } elseif( $num == 0 ) { # Don't show the 'no text matches' if we received title matches @@ -341,8 +362,8 @@ class SpecialSearch { //$contextlines = $wgUser->getOption( 'contextlines', 5 ); $contextlines = 2; // Hardcode this. Old defaults sucked. :) $contextchars = $wgUser->getOption( 'contextchars', 50 ); - - $link = $sk->makeKnownLinkObj( $t ); + + $link = $sk->makeKnownLinkObj( $t, $result->getTitleSnippet()); //If page content is not readable, just return the title. //This is not quite safe, but better than showing excerpts from non-readable pages @@ -360,12 +381,6 @@ class SpecialSearch { htmlspecialchars( $t->getPrefixedText() ) . "-->\n"; } - $text = $revision->getText(); - $size = wfMsgExt( 'search-result-size', array( 'parsemag', 'escape' ), - $sk->formatSize( strlen( $text ) ), - str_word_count( $text ) ); - $date = $wgLang->timeanddate( $revision->getTimestamp() ); - if( is_null( $result->getScore() ) ) { // Search engine doesn't report scoring info $score = ''; @@ -374,8 +389,51 @@ class SpecialSearch { $score = wfMsg( 'search-result-score', $wgLang->formatNum( $percent ) ) . ' - '; } - - $extract = $this->extractText( $text, $terms, $contextlines, $contextchars ); + + // try to fetch everything from the search engine backend + // then fill-in what couldn't be fetched + $extract = $result->getTextSnippet(); + $byteSize = $result->getByteSize(); + $wordCount = $result->getWordCount(); + $timestamp = $result->getTimestamp(); + $redirectTitle = $result->getRedirectTitle(); + $redirectText = $result->getRedirectSnippet(); + $sectionTitle = $result->getSectionTitle(); + $sectionText = $result->getSectionSnippet(); + + // fallback + if( is_null($extract) || is_null($wordCount) || is_null($byteSize) ){ + $text = $revision->getText(); + if( is_null($extract) ) + $extract = $this->extractText( $text, $terms, $contextlines, $contextchars ); + if( is_null($byteSize) ) + $byteSize = strlen( $text ); + if( is_null($wordCount) ) + $wordCount = str_word_count( $text ); + } + if( is_null($timestamp) ){ + $timestamp = $revision->getTimestamp(); + } + + // format description + $size = wfMsgExt( 'search-result-size', array( 'parsemag', 'escape' ), + $sk->formatSize( $byteSize ), + $wordCount ); + $date = $wgLang->timeanddate( $timestamp ); + + // format redirects / sections + $redirect = ''; + if( !is_null($redirectTitle) ) + $redirect = "" + .wfMsg('search-redirect',$sk->makeKnownLinkObj( $redirectTitle, $redirectText)) + .""; + $section = ''; + if( !is_null($sectionTitle) ) + $section = "" + .wfMsg('search-section', $sk->makeKnownLinkObj( $sectionTitle, $sectionText)) + .""; + // wrap extract + $extract = "
".$extract."
"; // Include a thumbnail for media files... if( $t->getNamespace() == NS_IMAGE ) { @@ -408,7 +466,7 @@ class SpecialSearch { } wfProfileOut( $fname ); - return "
  • {$link} {$extract}\n" . + return "
  • {$link} {$redirect} {$section} {$extract}\n" . "
    {$score}{$size} - {$date}
    " . "
  • \n"; @@ -437,12 +495,12 @@ class SpecialSearch { continue; } --$contextlines; - $pre = $wgContLang->truncate( $m[1], -$contextchars, '...' ); + $pre = $wgContLang->truncate( $m[1], -$contextchars, ' ... ' ); if ( count( $m ) < 3 ) { $post = ''; } else { - $post = $wgContLang->truncate( $m[3], $contextchars, '...' ); + $post = $wgContLang->truncate( $m[3], $contextchars, ' ... ' ); } $found = $m[2]; @@ -452,7 +510,7 @@ class SpecialSearch { $line = preg_replace( $pat2, "\\1", $line ); - $extract .= "
    {$line}\n"; + $extract .= "${line}\n"; } wfProfileOut( "$fname-extract" ); diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 86e34fde47..31221c117b 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -1231,8 +1231,12 @@ Make sure that this change will maintain historical page continuity. 'viewprevnext' => 'View ($1) ($2) ($3)', 'search-result-size' => '$1 ({{PLURAL:$2|1 word|$2 words}})', 'search-result-score' => 'Relevance: $1%', +'search-redirect' => '(redirect $1)', +'search-section' => '(section $1)', +'search-suggest' => 'Did you mean: $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 results '''$1 - $2''' of '''$3'''", 'nonefound' => "'''Note''': Unsuccessful searches are often caused by searching for common words like \"have\" and \"from\", which are not indexed, or by specifying more than one search term (only pages containing all of the search terms will appear in the result).", 'powersearch' => 'Advanced search', 'powersearch-legend' => 'Advanced search', diff --git a/skins/monobook/main.css b/skins/monobook/main.css index ba53bf26be..b3908f89a1 100644 --- a/skins/monobook/main.css +++ b/skins/monobook/main.css @@ -1184,8 +1184,23 @@ span.unpatrolled { } span.searchmatch { - color: red; + font-size: 95%; +} +div.searchresult { + font-size: 95%; + width:38em; +} + +span.searchalttitle { + font-size: 95%; } + +div.searchdidyoumean { + font-size: 127%; + padding-bottom:1ex; + padding-top:1ex; +} + .sharedUploadNotice { font-style: italic; }