Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/vendor/wikimedia/parsoid/src/Wt2Html/DOM/Processors/AddMediaInfo.php
Ðазад
<?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Wt2Html\DOM\Processors; use Wikimedia\Assert\Assert; use Wikimedia\Parsoid\Config\Env; use Wikimedia\Parsoid\Core\ContentMetadataCollectorStringSets as CMCSS; use Wikimedia\Parsoid\Core\Sanitizer; use Wikimedia\Parsoid\DOM\DocumentFragment; use Wikimedia\Parsoid\DOM\Element; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\Html2Wt\WTSUtils; use Wikimedia\Parsoid\NodeData\DataMw; use Wikimedia\Parsoid\NodeData\DataMwError; use Wikimedia\Parsoid\Utils\ContentUtils; use Wikimedia\Parsoid\Utils\DOMCompat; use Wikimedia\Parsoid\Utils\DOMDataUtils; use Wikimedia\Parsoid\Utils\DOMUtils; use Wikimedia\Parsoid\Utils\Title; use Wikimedia\Parsoid\Utils\WTUtils; use Wikimedia\Parsoid\Wikitext\Consts; use Wikimedia\Parsoid\Wt2Html\PegTokenizer; use Wikimedia\Parsoid\Wt2Html\Wt2HtmlDOMProcessor; class AddMediaInfo implements Wt2HtmlDOMProcessor { /** * Extract the dimensions for media. * * @param Env $env * @param array $attrs * @param array $info * @phan-param array{size:array{height?:int,width?:int},format:string} $attrs * @return array */ private static function handleSize( Env $env, array $attrs, array $info ): array { $height = $info['height']; $width = $info['width']; Assert::invariant( is_numeric( $height ) && $height !== NAN, 'Expected $height as a valid number' ); Assert::invariant( is_numeric( $width ) && $width !== NAN, 'Expected $width as a valid number' ); if ( !empty( $info['thumburl'] ) && !empty( $info['thumbheight'] ) ) { $height = $info['thumbheight']; } if ( !empty( $info['thumburl'] ) && !empty( $info['thumbwidth'] ) ) { $width = $info['thumbwidth']; } // Audio files don't have dimensions, so we fallback to these arbitrary // defaults, and the "mw-default-audio-height" class is added. if ( $info['mediatype'] === 'AUDIO' ) { // FIXME: TMH uses 23 but VE wants 32 $height = /* height || */32; // Arguably, audio should respect a defined height $width = max( 35, $width ?: $env->getSiteConfig()->widthOption() ); } // Handle client-side upscaling (including 'border') $mustRender = $info['mustRender'] ?? $info['mediatype'] !== 'BITMAP'; // Calculate the scaling ratio from the user-specified width and height $ratio = null; if ( !empty( $attrs['dims']['height'] ) && !empty( $info['height'] ) ) { $ratio = $attrs['dims']['height'] / $info['height']; } if ( !empty( $attrs['dims']['width'] ) && !empty( $info['width'] ) ) { $r = $attrs['dims']['width'] / $info['width']; $ratio = ( $ratio === null || $r < $ratio ) ? $r : $ratio; } // If the user requested upscaling, then this is denied in the thumbnail // and frameless format, except for files with mustRender. if ( $ratio !== null && $ratio > 1 && !$mustRender && ( $attrs['format'] === 'Thumb' || $attrs['format'] === 'Frameless' ) ) { // Upscaling denied $height = $info['height']; $width = $info['width']; } return [ 'height' => $height, 'width' => $width ]; } /** * This is a port of TMH's parseTimeString() * * @param string $timeString * @param int|float|null $length * @return int|float|null */ private static function parseTimeString( string $timeString, $length = null ) { $parts = explode( ':', $timeString ); $time = 0; $countParts = count( $parts ); if ( $countParts > 3 ) { return null; } for ( $i = 0; $i < $countParts; $i++ ) { if ( !is_numeric( $parts[$i] ) ) { return null; } $time += floatval( $parts[$i] ) * pow( 60, $countParts - 1 - $i ); } if ( $time < 0 ) { $time = 0; } elseif ( $length !== null ) { if ( $time > $length ) { $time = $length - 1; } } return $time; } /** * Handle media fragments * https://www.w3.org/TR/media-frags/ * * @param array $info * @param DataMw $dataMw * @return string */ private static function parseFrag( array $info, DataMw $dataMw ): string { $frag = ''; $starttime = WTSUtils::getAttrFromDataMw( $dataMw, 'starttime', true ); $endtime = WTSUtils::getAttrFromDataMw( $dataMw, 'endtime', true ); if ( $starttime || $endtime ) { $frag .= '#t='; if ( $starttime ) { $time = self::parseTimeString( $starttime->value['txt'], $info['duration'] ?? null ); if ( $time !== null ) { $frag .= $time; } } if ( $endtime ) { $time = self::parseTimeString( $endtime->value['txt'], $info['duration'] ?? null ); if ( $time !== null ) { $frag .= ',' . $time; } } } return $frag; } private static function addSources( Element $elt, array $info, DataMw $dataMw, bool $hasDimension ): void { $doc = $elt->ownerDocument; $frag = self::parseFrag( $info, $dataMw ); if ( is_array( $info['thumbdata']['derivatives'] ?? null ) ) { // BatchAPI's `getAPIData` $derivatives = $info['thumbdata']['derivatives']; } elseif ( is_array( $info['derivatives'] ?? null ) ) { // "videoinfo" prop $derivatives = $info['derivatives']; } else { $derivatives = [ [ 'src' => $info['url'], 'type' => $info['mime'], 'width' => (string)$info['width'], 'height' => (string)$info['height'], ], ]; } foreach ( $derivatives as $o ) { $source = $doc->createElement( 'source' ); $source->setAttribute( 'src', $o['src'] . $frag ); $source->setAttribute( 'type', $o['type'] ); // T339375 $fromFile = isset( $o['transcodekey'] ) ? '' : '-file'; if ( $hasDimension ) { $source->setAttribute( 'data' . $fromFile . '-width', (string)$o['width'] ); $source->setAttribute( 'data' . $fromFile . '-height', (string)$o['height'] ); } if ( !$fromFile ) { $source->setAttribute( 'data-transcodekey', $o['transcodekey'] ); } $elt->appendChild( $source ); } } private static function addTracks( Element $elt, array $info ): void { $doc = $elt->ownerDocument; if ( is_array( $info['thumbdata']['timedtext'] ?? null ) ) { // BatchAPI's `getAPIData` $timedtext = $info['thumbdata']['timedtext']; } elseif ( is_array( $info['timedtext'] ?? null ) ) { // "videoinfo" prop $timedtext = $info['timedtext']; } else { $timedtext = []; } foreach ( $timedtext as $o ) { $track = $doc->createElement( 'track' ); $track->setAttribute( 'kind', $o['kind'] ?? '' ); $track->setAttribute( 'type', $o['type'] ?? '' ); $track->setAttribute( 'src', $o['src'] ?? '' ); $track->setAttribute( 'srclang', $o['srclang'] ?? '' ); $track->setAttribute( 'label', $o['label'] ?? '' ); $track->setAttribute( 'data-mwtitle', $o['title'] ?? '' ); $track->setAttribute( 'data-dir', $o['dir'] ?? '' ); $elt->appendChild( $track ); } } /** * Abstract way to get the path for an image given an info object. * * @param array $info * @return string */ private static function getPath( array $info ) { $path = ''; if ( !empty( $info['thumburl'] ) ) { $path = $info['thumburl']; } elseif ( !empty( $info['url'] ) ) { $path = $info['url']; } return $path; } /** * @param Env $env * @param Element $span * @param array $attrs * @param array $info * @param DataMw $dataMw * @param Element $container * @param string|null $alt Unused, but matches the signature of handlers * @return Element */ private static function handleAudio( Env $env, Element $span, array $attrs, array $info, DataMw $dataMw, Element $container, ?string $alt ): Element { $doc = $span->ownerDocument; $audio = $doc->createElement( 'audio' ); $audio->setAttribute( 'controls', '' ); $audio->setAttribute( 'preload', 'none' ); $muted = WTSUtils::getAttrFromDataMw( $dataMw, 'muted', false ); if ( $muted ) { $audio->setAttribute( 'muted', '' ); } $loop = WTSUtils::getAttrFromDataMw( $dataMw, 'loop', false ); if ( $loop ) { $audio->setAttribute( 'loop', '' ); } // HACK(T295514): Until T313875 is implemented $audio->setAttribute( 'data-mw-tmh', '' ); $size = self::handleSize( $env, $attrs, $info ); DOMDataUtils::addNormalizedAttribute( $audio, 'height', (string)$size['height'], null, true ); DOMDataUtils::addNormalizedAttribute( $audio, 'width', (string)$size['width'], null, true ); $audio->setAttribute( 'style', "width: {$size['width']}px;" ); // Hardcoded until defined heights are respected. // See `AddMediaInfo::handleSize` DOMCompat::getClassList( $container )->add( 'mw-default-audio-height' ); self::copyOverAttribute( $audio, $span, 'resource' ); if ( $span->hasAttribute( 'lang' ) ) { self::copyOverAttribute( $audio, $span, 'lang' ); } if ( $info['duration'] ?? null ) { $audio->setAttribute( 'data-durationhint', (string)ceil( (float)$info['duration'] ) ); } self::addSources( $audio, $info, $dataMw, false ); self::addTracks( $audio, $info ); return $audio; } /** * @param Env $env * @param Element $span * @param array $attrs * @param array $info * @param DataMw $dataMw * @param Element $container * @param string|null $alt Unused, but matches the signature of handlers * @return Element */ private static function handleVideo( Env $env, Element $span, array $attrs, array $info, DataMw $dataMw, Element $container, ?string $alt ): Element { $doc = $span->ownerDocument; $video = $doc->createElement( 'video' ); if ( !empty( $info['thumburl'] ) ) { $video->setAttribute( 'poster', self::getPath( $info ) ); } $video->setAttribute( 'controls', '' ); $video->setAttribute( 'preload', 'none' ); $muted = WTSUtils::getAttrFromDataMw( $dataMw, 'muted', false ); if ( $muted ) { $video->setAttribute( 'muted', '' ); } $loop = WTSUtils::getAttrFromDataMw( $dataMw, 'loop', false ); if ( $loop ) { $video->setAttribute( 'loop', '' ); } // HACK(T295514): Until T313875 is implemented $video->setAttribute( 'data-mw-tmh', '' ); $size = self::handleSize( $env, $attrs, $info ); DOMDataUtils::addNormalizedAttribute( $video, 'height', (string)$size['height'], null, true ); DOMDataUtils::addNormalizedAttribute( $video, 'width', (string)$size['width'], null, true ); self::copyOverAttribute( $video, $span, 'resource' ); if ( $span->hasAttribute( 'lang' ) ) { self::copyOverAttribute( $video, $span, 'lang' ); } if ( $info['duration'] ?? null ) { $video->setAttribute( 'data-durationhint', (string)ceil( (float)$info['duration'] ) ); } self::addSources( $video, $info, $dataMw, true ); self::addTracks( $video, $info ); return $video; } /** * Set up the actual image structure, attributes, etc. * * @param Env $env * @param Element $span * @param array $attrs * @param array $info * @param DataMw $dataMw * @param Element $container * @param string|null $alt * @return Element */ private static function handleImage( Env $env, Element $span, array $attrs, array $info, DataMw $dataMw, Element $container, ?string $alt ): Element { $doc = $span->ownerDocument; $img = $doc->createElement( 'img' ); if ( $alt !== null ) { $img->setAttribute( 'alt', $alt ); } self::copyOverAttribute( $img, $span, 'resource' ); $img->setAttribute( 'src', self::getPath( $info ) ); $img->setAttribute( 'decoding', 'async' ); if ( $span->hasAttribute( 'lang' ) ) { self::copyOverAttribute( $img, $span, 'lang' ); } // Add (read-only) information about original file size (T64881) $img->setAttribute( 'data-file-width', (string)$info['width'] ); $img->setAttribute( 'data-file-height', (string)$info['height'] ); $img->setAttribute( 'data-file-type', strtolower( $info['mediatype'] ?? '' ) ); $size = self::handleSize( $env, $attrs, $info ); DOMDataUtils::addNormalizedAttribute( $img, 'height', (string)$size['height'], null, true ); DOMDataUtils::addNormalizedAttribute( $img, 'width', (string)$size['width'], null, true ); // Handle "responsive" images, i.e. srcset if ( !empty( $info['responsiveUrls'] ) ) { $candidates = []; foreach ( $info['responsiveUrls'] as $density => $url ) { $candidates[] = $url . ' ' . $density . 'x'; } if ( $candidates ) { $img->setAttribute( 'srcset', implode( ', ', $candidates ) ); } } return $img; } private static function makeErr( string $key, string $message, ?array $params = null ): DataMwError { return new DataMwError( $key, $params ?? [], $message ); } /** * @param Element $container * @param Element $span * @param list<DataMwError> $errs * @param DataMw $dataMw * @param ?string $alt */ private static function handleErrors( Element $container, Element $span, array $errs, DataMw $dataMw, ?string $alt ): void { if ( !DOMUtils::hasTypeOf( $container, 'mw:Error' ) ) { DOMUtils::addTypeOf( $container, 'mw:Error', true ); } if ( is_array( $dataMw->errors ?? null ) ) { $errs = array_merge( $dataMw->errors, $errs ); } $dataMw->errors = $errs; if ( $alt !== null ) { DOMCompat::replaceChildren( $span, $span->ownerDocument->createTextNode( $alt ) ); } } private static function copyOverAttribute( Element $elt, Element $span, string $attribute ): void { DOMDataUtils::addNormalizedAttribute( $elt, $attribute, DOMCompat::getAttribute( $span, $attribute ), WTSUtils::getAttributeShadowInfo( $span, $attribute )['value'] ); } private static function replaceAnchor( Env $env, PegTokenizer $urlParser, Element $container, Element $oldAnchor, array $attrs, DataMw $dataMw, bool $isImage, ?string $captionText, int $page, string $lang ): Element { $doc = $oldAnchor->ownerDocument; $attr = WTSUtils::getAttrFromDataMw( $dataMw, 'link', true ); if ( $isImage ) { $anchor = $doc->createElement( 'a' ); $addDescriptionLink = static function ( Title $title ) use ( $env, $anchor, $page, $lang ) { $href = $env->makeLink( $title ); $qs = []; if ( $page > 0 ) { $qs['page'] = $page; } if ( $lang ) { $qs['lang'] = $lang; } if ( $qs ) { $href .= '?' . http_build_query( $qs ); } $anchor->setAttribute( 'href', $href ); $anchor->setAttribute( 'class', 'mw-file-description' ); }; if ( $attr !== null ) { $discard = true; $val = $attr->value['txt']; if ( $val === '' ) { // No href if link= was specified $anchor = $doc->createElement( 'span' ); } elseif ( $urlParser->tokenizeURL( $val ) !== false ) { // An external link! $href = Sanitizer::cleanUrl( $env->getSiteConfig(), $val, 'external' ); $anchor->setAttribute( 'href', $href ); // Similar to AddLinkAttributes $extLinkAttribs = $env->getExternalLinkAttribs( $href ); foreach ( $extLinkAttribs as $key => $val ) { if ( $key === 'rel' ) { foreach ( $val as $v ) { DOMUtils::addRel( $anchor, $v ); } } else { $anchor->setAttribute( $key, $val ); } } } else { $link = $env->makeTitleFromText( $val, null, true ); if ( $link !== null ) { $anchor->setAttribute( 'href', $env->makeLink( $link ) ); $anchor->setAttribute( 'title', $link->getPrefixedText() ); } else { // Treat same as if link weren't present $addDescriptionLink( $attrs['title'] ); // but preserve for roundtripping $discard = false; } } if ( $discard ) { WTSUtils::getAttrFromDataMw( $dataMw, 'link', /* keep */false ); } } else { $addDescriptionLink( $attrs['title'] ); } } else { $anchor = $doc->createElement( 'span' ); } if ( $captionText ) { $anchor->setAttribute( 'title', $captionText ); } $oldAnchor->parentNode->replaceChild( $anchor, $oldAnchor ); return $anchor; } /** * @inheritDoc */ public function run( Env $env, Node $root, array $options = [], bool $atTopLevel = false ): void { '@phan-var Element|DocumentFragment $root'; // @var Element|DocumentFragment $root $urlParser = new PegTokenizer( $env ); $validContainers = []; $files = []; $containers = DOMCompat::querySelectorAll( $root, '[typeof*="mw:File"]' ); foreach ( $containers as $container ) { // DOMFragmentWrappers assume the element name of their outermost // content so, depending how the above query is written, we're // protecting against getting a figure of the wrong type. However, // since we're currently using typeof, it shouldn't be a problem. // Also note that info for the media nested in the fragment has // already been added in their respective pipeline. Assert::invariant( !WTUtils::isDOMFragmentWrapper( $container ), 'Media info for fragment was already added' ); // We expect this structure to be predictable based on how it's // emitted in the TT/WikiLinkHandler but treebuilding may have // messed that up for us. $anchor = $container; $reopenedAFE = []; do { // An active formatting element may have been reopened inside // the wrapper if a content model violation was encountered // during treebuiling. Try to be a little lenient about that // instead of bailing out $anchor = $anchor->firstChild; $anchorNodeName = DOMCompat::nodeName( $anchor ); if ( $anchorNodeName !== 'a' ) { $reopenedAFE[] = $anchor; } } while ( $anchorNodeName !== 'a' && isset( Consts::$HTML['FormattingTags'][$anchorNodeName] ) ); if ( $anchorNodeName !== 'a' ) { $env->log( 'error', 'Unexpected structure when adding media info.' ); continue; } $span = $anchor->firstChild; if ( !( $span instanceof Element && DOMCompat::nodeName( $span ) === 'span' ) ) { $env->log( 'error', 'Unexpected structure when adding media info.' ); continue; } $caption = $anchor->nextSibling; $isInlineMedia = WTUtils::isInlineMedia( $container ); if ( !$isInlineMedia && DOMCompat::nodeName( $caption ) !== 'figcaption' ) { $env->log( 'error', 'Unexpected structure when adding media info.' ); continue; } // For T314059. Migrate any active formatting tags we found open // inside the container to the ficaption to conform to the spec. // This should simplify selectors for clients and styling. // TODO: Consider exposing these as lints if ( $reopenedAFE ) { $firstAFE = $reopenedAFE[0]; $lastAFE = $reopenedAFE[count( $reopenedAFE ) - 1]; DOMUtils::migrateChildren( $lastAFE, $container ); if ( $isInlineMedia ) { // Remove the formatting elements, they are of no use // We could migrate them into the caption in data-mw, // but that doesn't seem worthwhile $firstAFE->parentNode->removeChild( $firstAFE ); } else { // Move the formatting elements into the figcaption DOMUtils::migrateChildren( $caption, $lastAFE ); $caption->appendChild( $firstAFE ); // Unconditionally clear tsr out of an abundance of caution // These tags should already be annotated as autoinserted anyways foreach ( $reopenedAFE as $afe ) { DOMDataUtils::getDataParsoid( $afe )->tsr = null; } } } $dataMw = DOMDataUtils::getDataMw( $container ); $dims = [ 'width' => (int)DOMCompat::getAttribute( $span, 'data-width' ) ?: null, 'height' => (int)DOMCompat::getAttribute( $span, 'data-height' ) ?: null, ]; $page = WTSUtils::getAttrFromDataMw( $dataMw, 'page', true ); if ( $page ) { $dims['page'] = $page->value['txt']; } $lang = DOMCompat::getAttribute( $span, 'lang' ); if ( $lang !== null ) { $dims['lang'] = $lang; } // "starttime" should be used if "thumbtime" isn't present, // but only for rendering. // "starttime" should be used if "thumbtime" isn't present, // but only for rendering. $thumbtime = WTSUtils::getAttrFromDataMw( $dataMw, 'thumbtime', true ); $starttime = WTSUtils::getAttrFromDataMw( $dataMw, 'starttime', true ); if ( $thumbtime || $starttime ) { $seek = isset( $thumbtime->value ) ? $thumbtime->value['txt'] : ( isset( $starttime->value ) ? $starttime->value['txt'] : '' ); $seek = self::parseTimeString( $seek ); if ( $seek !== null ) { $dims['seek'] = $seek; } } $attrs = [ 'dims' => $dims, 'format' => WTUtils::getMediaFormat( $container ), 'title' => $env->makeTitleFromText( $span->textContent ), ]; $file = [ $attrs['title']->getDBKey(), $dims ]; $infoKey = md5( json_encode( $file ) ); $files[$infoKey] = $file; $errs = []; $manualKey = null; $manualthumb = WTSUtils::getAttrFromDataMw( $dataMw, 'manualthumb', true ); if ( $manualthumb !== null ) { $val = $manualthumb->value['txt']; $title = $env->makeTitleFromText( $val, $attrs['title']->getNamespace(), true ); if ( $title === null ) { $errs[] = self::makeErr( 'apierror-invalidtitle', 'Invalid thumbnail title.', [ 'name' => $val ] ); } else { $file = [ $title->getDBkey(), $dims ]; $manualKey = md5( json_encode( $file ) ); $files[$manualKey] = $file; } } $validContainers[] = [ 'container' => $container, 'attrs' => $attrs, // Pass the anchor because we did some work to find it above 'anchor' => $anchor, 'infoKey' => $infoKey, 'manualKey' => $manualKey, 'errs' => $errs, ]; } if ( !$validContainers ) { return; } $start = microtime( true ); $infos = $env->getDataAccess()->getFileInfo( $env->getPageConfig(), array_values( $files ) ); if ( $env->profiling() ) { $profile = $env->getCurrentProfile(); $profile->bumpMWTime( "Media", 1000 * ( microtime( true ) - $start ), "api" ); $profile->bumpCount( "Media" ); } $files = array_combine( array_keys( $files ), $infos ); $hasThumb = false; $needsTMHModules = false; foreach ( $validContainers as $c ) { $container = $c['container']; $anchor = $c['anchor']; $span = $anchor->firstChild; $attrs = $c['attrs']; $dataMw = DOMDataUtils::getDataMw( $container ); $errs = $c['errs']; $hasThumb = $hasThumb || DOMUtils::hasTypeOf( $container, 'mw:File/Thumb' ); $info = $files[$c['infoKey']]; if ( !$info ) { $env->getDataAccess()->addTrackingCategory( $env->getPageConfig(), $env->getMetadata(), 'broken-file-category' ); $errs[] = self::makeErr( 'apierror-filedoesnotexist', 'This image does not exist.' ); } elseif ( isset( $info['thumberror'] ) ) { $errs[] = self::makeErr( 'apierror-unknownerror', $info['thumberror'] ); } // FIXME: Should we fallback to $info if there are errors with $manualinfo? // What does the legacy parser do? if ( $c['manualKey'] !== null ) { $manualinfo = $files[$c['manualKey']]; if ( !$manualinfo ) { $errs[] = self::makeErr( 'apierror-filedoesnotexist', 'This image does not exist.' ); } elseif ( isset( $manualinfo['thumberror'] ) ) { $errs[] = self::makeErr( 'apierror-unknownerror', $manualinfo['thumberror'] ); } else { $info = $manualinfo; } } if ( $info['badFile'] ?? false ) { $errs[] = self::makeErr( 'apierror-badfile', 'This image is on the bad file list.' ); } if ( WTUtils::hasVisibleCaption( $container ) ) { $captionText = null; } else { if ( WTUtils::isInlineMedia( $container ) ) { $caption = ContentUtils::createAndLoadDocumentFragment( $container->ownerDocument, $dataMw->caption ?? '' ); } else { $caption = DOMCompat::querySelector( $container, 'figcaption' ); // If the caption had tokens, it was placed in a DOMFragment // and we haven't unpacked yet if ( $caption->firstChild && DOMUtils::hasTypeOf( $caption->firstChild, 'mw:DOMFragment' ) ) { $id = DOMDataUtils::getDataParsoid( $caption->firstChild )->html; $caption = $env->getDOMFragment( $id ); } } $captionText = trim( WTUtils::textContentFromCaption( $caption ) ); // The sanitizer isn't going to do anything with a string value // for alt/title and since we're going to use dom element setters, // quote escaping should be fine. Note that if sanitization does // happen here, it should also be done to $altFromCaption so that // string comparison matches, where necessary. // // $sanitizedArgs = Sanitizer::sanitizeTagAttrs( $env->getSiteConfig(), 'img', null, [ // new KV( 'alt', $captionText ) // Could be a 'title' too // ] ); // $captionText = $sanitizedArgs['alt']->key; } // Info relates to the thumb, not necessarily the file. // The distinction matters for manualthumb, in which case only // the "resource" copied over from the span relates to the file. switch ( $info['mediatype'] ?? '' ) { case 'AUDIO': $handler = 'handleAudio'; $isImage = false; break; case 'VIDEO': $handler = 'handleVideo'; $isImage = false; break; default: $handler = 'handleImage'; $isImage = true; break; } $alt = null; $keepAltInDataMw = !$isImage || $errs; $attr = WTSUtils::getAttrFromDataMw( $dataMw, 'alt', $keepAltInDataMw ); if ( $attr !== null ) { $alt = $attr->value['txt']; } elseif ( $captionText ) { $alt = $captionText; } // Add mw:Error to the RDFa type. if ( $errs ) { self::handleErrors( $container, $span, $errs, $dataMw, $alt ); continue; } $needsTMHModules = $needsTMHModules || !$isImage; $env->getMetadata()->addImage( $attrs['title'], $info['timestamp'] ?? null, $info['sha1'] ?? null, ); $elt = self::$handler( $env, $span, $attrs, $info, $dataMw, $container, $alt ); DOMCompat::getClassList( $elt )->add( 'mw-file-element' ); $anchor = self::replaceAnchor( $env, $urlParser, $container, $anchor, $attrs, $dataMw, $isImage, $captionText, (int)( $attrs['dims']['page'] ?? 0 ), $attrs['dims']['lang'] ?? '' ); $anchor->appendChild( $elt ); if ( isset( $dataMw->attribs ) && count( $dataMw->attribs ) === 0 ) { unset( $dataMw->attribs ); } } if ( $hasThumb ) { $env->getMetadata()->appendOutputStrings( CMCSS::MODULE, [ 'mediawiki.page.media' ] ); } if ( $needsTMHModules ) { $env->getMetadata()->appendOutputStrings( CMCSS::MODULE_STYLE, [ 'ext.tmh.player.styles' ] ); $env->getMetadata()->appendOutputStrings( CMCSS::MODULE, [ 'ext.tmh.player' ] ); } } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка