Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/includes/search/searchwidgets/FullSearchResultWidget.php
Ðазад
<?php namespace MediaWiki\Search\SearchWidgets; use File; use HtmlArmor; use MediaTransformOutput; use MediaWiki\Category\Category; use MediaWiki\HookContainer\HookContainer; use MediaWiki\HookContainer\HookRunner; use MediaWiki\Html\Html; use MediaWiki\Linker\LinkRenderer; use MediaWiki\MainConfigNames; use MediaWiki\Search\Entity\SearchResultThumbnail; use MediaWiki\Search\SearchResultThumbnailProvider; use MediaWiki\Specials\SpecialSearch; use MediaWiki\Title\Title; use MediaWiki\User\Options\UserOptionsManager; use RepoGroup; use SearchResult; use ThumbnailImage; /** * Renders a 'full' multi-line search result with metadata. * * The Title * some *highlighted* *text* about the search result * 5 KiB (651 words) - 12:40, 6 Aug 2016 */ class FullSearchResultWidget implements SearchResultWidget { public const THUMBNAIL_SIZE = 90; /** @var SpecialSearch */ protected $specialPage; /** @var LinkRenderer */ protected $linkRenderer; /** @var HookRunner */ private $hookRunner; /** @var RepoGroup */ private $repoGroup; /** @var SearchResultThumbnailProvider */ private $thumbnailProvider; /** @var string */ private $thumbnailPlaceholderHtml; /** @var UserOptionsManager */ private $userOptionsManager; public function __construct( SpecialSearch $specialPage, LinkRenderer $linkRenderer, HookContainer $hookContainer, RepoGroup $repoGroup, SearchResultThumbnailProvider $thumbnailProvider, UserOptionsManager $userOptionsManager ) { $this->specialPage = $specialPage; $this->linkRenderer = $linkRenderer; $this->hookRunner = new HookRunner( $hookContainer ); $this->repoGroup = $repoGroup; $this->thumbnailProvider = $thumbnailProvider; $this->userOptionsManager = $userOptionsManager; } /** * @param SearchResult $result The result to render * @param int $position The result position, including offset * @return string HTML */ public function render( SearchResult $result, $position ) { // If the page doesn't *exist*... our search index is out of date. // The least confusing at this point is to drop the result. // You may get less results, but... on well. :P if ( $result->isBrokenTitle() || $result->isMissingRevision() ) { return ''; } $link = $this->generateMainLinkHtml( $result, $position ); // If page content is not readable, just return ths title. // This is not quite safe, but better than showing excerpts from // non-readable pages. Note that hiding the entry entirely would // screw up paging (really?). if ( !$this->specialPage->getAuthority()->definitelyCan( 'read', $result->getTitle() ) ) { return Html::rawElement( 'li', [], $link ); } $redirect = $this->generateRedirectHtml( $result ); $section = $this->generateSectionHtml( $result ); $category = $this->generateCategoryHtml( $result ); $date = htmlspecialchars( $this->specialPage->getLanguage()->userTimeAndDate( $result->getTimestamp(), $this->specialPage->getUser() ) ); [ $file, $desc, $thumb ] = $this->generateFileHtml( $result ); $snippet = $result->getTextSnippet(); if ( $snippet ) { $snippetWithEllipsis = $snippet . $this->specialPage->msg( 'ellipsis' ); $extract = Html::rawElement( 'div', [ 'class' => 'searchresult' ], $snippetWithEllipsis ); } else { $extract = ''; } if ( $result->getTitle() && $result->getTitle()->getNamespace() !== NS_FILE ) { // If no file, then the description is about size $desc = $this->generateSizeHtml( $result ); // Let hooks do their own final construction if desired. // FIXME: Not sure why this is only for results without thumbnails, // but keeping it as-is for now to prevent breaking hook consumers. $html = null; $score = ''; $related = ''; // TODO: remove this instanceof and always pass [], let implementors do the cast if // they want to be SearchDatabase specific $terms = $result instanceof \SqlSearchResult ? $result->getTermMatches() : []; if ( !$this->hookRunner->onShowSearchHit( $this->specialPage, $result, $terms, $link, $redirect, $section, $extract, $score, // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args $desc, $date, $related, $html ) ) { return $html; } } // All the pieces have been collected. Now generate the final HTML $joined = "{$link} {$redirect} {$category} {$section} {$file}"; $meta = $this->buildMeta( $desc, $date ); // Text portion of the search result $html = Html::rawElement( 'div', [ 'class' => 'mw-search-result-heading' ], $joined ); $html .= $extract . ' ' . $meta; // If the result has a thumbnail, place it next to the text block if ( $thumb ) { $gridCells = Html::rawElement( 'div', [ 'class' => 'searchResultImage-thumbnail' ], $thumb ) . Html::rawElement( 'div', [ 'class' => 'searchResultImage-text' ], $html ); $html = Html::rawElement( 'div', [ 'class' => 'searchResultImage' ], $gridCells ); } return Html::rawElement( 'li', [ 'class' => [ 'mw-search-result', 'mw-search-result-ns-' . $result->getTitle()->getNamespace() ] ], $html ); } /** * Generates HTML for the primary call to action. It is * typically the article title, but the search engine can * return an exact snippet to use (typically the article * title with highlighted words). * * @param SearchResult $result * @param int $position * @return string HTML */ protected function generateMainLinkHtml( SearchResult $result, $position ) { $snippet = $result->getTitleSnippet(); if ( $snippet === '' ) { $snippet = null; } else { $snippet = new HtmlArmor( $snippet ); } // clone to prevent hook from changing the title stored inside $result $title = clone $result->getTitle(); $query = []; $attributes = [ 'data-serp-pos' => $position ]; $this->hookRunner->onShowSearchHitTitle( $title, $snippet, $result, $result instanceof \SqlSearchResult ? $result->getTermMatches() : [], // @phan-suppress-next-line PhanTypeMismatchArgument Type mismatch on pass-by-ref args $this->specialPage, $query, $attributes ); $link = $this->linkRenderer->makeLink( $title, $snippet, $attributes, $query ); return $link; } /** * Generates an alternate title link, such as (redirect from <a>Foo</a>). * * @param string $msgKey i18n message used to wrap title * @param Title|null $title The title to link to, or null to generate * the message without a link. In that case $text must be non-null. * @param string|null $text The text snippet to display, or null * to use the title * @return string HTML */ protected function generateAltTitleHtml( $msgKey, ?Title $title, $text ) { $inner = $title === null ? $text : $this->linkRenderer->makeLink( $title, $text ? new HtmlArmor( $text ) : null ); return "<span class='searchalttitle'>" . $this->specialPage->msg( $msgKey )->rawParams( $inner )->parse() . "</span>"; } /** * @param SearchResult $result * @return string HTML */ protected function generateRedirectHtml( SearchResult $result ) { $title = $result->getRedirectTitle(); return $title === null ? '' : $this->generateAltTitleHtml( 'search-redirect', $title, $result->getRedirectSnippet() ); } /** * @param SearchResult $result * @return string HTML */ protected function generateSectionHtml( SearchResult $result ) { $title = $result->getSectionTitle(); return $title === null ? '' : $this->generateAltTitleHtml( 'search-section', $title, $result->getSectionSnippet() ); } /** * @param SearchResult $result * @return string HTML */ protected function generateCategoryHtml( SearchResult $result ) { $snippet = $result->getCategorySnippet(); return $snippet ? $this->generateAltTitleHtml( 'search-category', null, $snippet ) : ''; } /** * @param SearchResult $result * @return string HTML */ protected function generateSizeHtml( SearchResult $result ) { $title = $result->getTitle(); if ( $title->getNamespace() === NS_CATEGORY ) { $cat = Category::newFromTitle( $title ); return $this->specialPage->msg( 'search-result-category-size' ) ->numParams( $cat->getMemberCount(), $cat->getSubcatCount(), $cat->getFileCount() ) ->escaped(); // TODO: This is a bit odd...but requires changing the i18n message to fix } elseif ( $result->getByteSize() !== null || $result->getWordCount() > 0 ) { return $this->specialPage->msg( 'search-result-size' ) ->sizeParams( $result->getByteSize() ) ->numParams( $result->getWordCount() ) ->escaped(); } return ''; } /** * @param SearchResult $result * @return array Three element array containing the main file html, * a text description of the file, and finally the thumbnail html. * If no thumbnail is available the second and third will be null. */ protected function generateFileHtml( SearchResult $result ) { $title = $result->getTitle(); // don't assume that result is a valid title; e.g. could be an interwiki link target if ( $title === null || !$title->canExist() ) { return [ '', null, null ]; } $html = ''; if ( $result->isFileMatch() ) { $html = Html::rawElement( 'span', [ 'class' => 'searchalttitle' ], $this->specialPage->msg( 'search-file-match' )->escaped() ); } $allowExtraThumbsFromRequest = $this->specialPage->getRequest()->getVal( 'search-thumbnail-extra-namespaces' ); $allowExtraThumbsFromPreference = $this->userOptionsManager->getOption( $this->specialPage->getUser(), 'search-thumbnail-extra-namespaces' ); $allowExtraThumbs = (bool)( $allowExtraThumbsFromRequest ?? $allowExtraThumbsFromPreference ); if ( !$allowExtraThumbs && $title->getNamespace() !== NS_FILE ) { return [ $html, null, null ]; } $thumbnail = $this->getThumbnail( $result, self::THUMBNAIL_SIZE ); $thumbnailName = $thumbnail ? $thumbnail->getName() : null; if ( !$thumbnailName ) { return [ $html, null, $this->generateThumbnailHtml( $result ) ]; } $img = $this->repoGroup->findFile( $thumbnailName ); if ( !$img ) { return [ $html, null, $this->generateThumbnailHtml( $result ) ]; } return [ $html, $this->specialPage->msg( 'parentheses' )->rawParams( $img->getShortDesc() )->escaped(), $this->generateThumbnailHtml( $result, $thumbnail ) ]; } /** * @param SearchResult $result * @param int $size * @return SearchResultThumbnail|null */ private function getThumbnail( SearchResult $result, int $size ): ?SearchResultThumbnail { $title = $result->getTitle(); // don't assume that result is a valid title; e.g. could be an interwiki link target if ( $title === null || !$title->canExist() ) { return null; } $thumbnails = $this->thumbnailProvider->getThumbnails( [ $title->getArticleID() => $title ], $size ); return $thumbnails[ $title->getArticleID() ] ?? null; } /** * @param SearchResult $result * @param SearchResultThumbnail|null $thumbnail * @return string|null */ private function generateThumbnailHtml( SearchResult $result, ?SearchResultThumbnail $thumbnail = null ): ?string { $title = $result->getTitle(); // don't assume that result is a valid title; e.g. could be an interwiki link target if ( $title === null || !$title->canExist() ) { return null; } $namespacesWithThumbnails = $this->specialPage->getConfig()->get( MainConfigNames::ThumbnailNamespaces ); $showThumbnail = in_array( $title->getNamespace(), $namespacesWithThumbnails ); if ( !$showThumbnail ) { return null; } $thumbnailName = $thumbnail ? $thumbnail->getName() : null; if ( !$thumbnail || !$thumbnailName ) { return $this->generateThumbnailPlaceholderHtml(); } $img = $this->repoGroup->findFile( $thumbnailName ); if ( !$img ) { return $this->generateThumbnailPlaceholderHtml(); } $thumb = $this->transformThumbnail( $img, $thumbnail ); if ( $thumb ) { if ( $title->getNamespace() === NS_FILE ) { // don't use a custom link, just use traditional thumbnail HTML return $thumb->toHtml( [ 'desc-link' => true, 'loading' => 'lazy', 'alt' => $this->specialPage->msg( 'search-thumbnail-alt' )->params( $title ), ] ); } // thumbnails for non-file results should link to the relevant title return $thumb->toHtml( [ 'desc-link' => true, 'custom-title-link' => $title, 'loading' => 'lazy', 'alt' => $this->specialPage->msg( 'search-thumbnail-alt' )->params( $title ), ] ); } return $this->generateThumbnailPlaceholderHtml(); } /** * @param File $img * @param SearchResultThumbnail $thumbnail * @return ThumbnailImage|MediaTransformOutput|bool False on failure */ private function transformThumbnail( File $img, SearchResultThumbnail $thumbnail ) { $optimalThumbnailWidth = $thumbnail->getWidth(); // $thumb will have rescaled to fit within a <$size>x<$size> bounding // box, but we want it to cover a full square (at the cost of losing // some of the edges) // instead of the largest side matching up with $size, we want the // smallest size to match (or exceed) $size $thumbnailMaxDimension = max( $thumbnail->getWidth(), $thumbnail->getHeight() ); $thumbnailMinDimension = min( $thumbnail->getWidth(), $thumbnail->getHeight() ); $rescaleCoefficient = $thumbnailMinDimension ? $thumbnailMaxDimension / $thumbnailMinDimension : 1; // we'll only deal with width from now on since conventions for // standard sizes have formed around width; height will simply // follow according to aspect ratio $rescaledWidth = (int)round( $rescaleCoefficient * $thumbnail->getWidth() ); // we'll also be looking at $wgThumbLimits to ensure that we pick // from within the predefined list of sizes // NOTE: only do this when there is a difference in the rescaled // size vs the original thumbnail size - some media types are // different and thumb limits don't matter (e.g. for audio, the // player must remain at the size we want, regardless of whether or // not it fits the thumb limits, which in this case are irrelevant) if ( $rescaledWidth !== $thumbnail->getWidth() ) { $thumbLimits = $this->specialPage->getConfig()->get( MainConfigNames::ThumbLimits ); $largerThumbLimits = array_filter( $thumbLimits, static function ( $limit ) use ( $rescaledWidth ) { return $limit >= $rescaledWidth; } ); $optimalThumbnailWidth = $largerThumbLimits ? min( $largerThumbLimits ) : max( $thumbLimits ); } return $img->transform( [ 'width' => $optimalThumbnailWidth ] ); } /** * @return string */ private function generateThumbnailPlaceholderHtml(): string { if ( $this->thumbnailPlaceholderHtml ) { return $this->thumbnailPlaceholderHtml; } $path = MW_INSTALL_PATH . '/resources/lib/ooui/themes/wikimediaui/images/icons/imageLayoutFrameless.svg'; $this->thumbnailPlaceholderHtml = Html::rawElement( 'div', [ 'class' => 'searchResultImage-thumbnail-placeholder', 'aria-hidden' => 'true', ], file_get_contents( $path ) ); return $this->thumbnailPlaceholderHtml; } /** * @param string $desc HTML description of result, ex: size in bytes, or empty string * @param string $date HTML representation of last edit date, or empty string * @return string HTML A div combining $desc and $date with a separator in a <div>. * If either is missing only one will be represented. If both are missing an empty * string will be returned. */ protected function buildMeta( $desc, $date ) { if ( $desc && $date ) { $meta = "{$desc} - {$date}"; } elseif ( $desc ) { $meta = $desc; } elseif ( $date ) { $meta = $date; } else { return ''; } return "<div class='mw-search-result-data'>{$meta}</div>"; } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка