. * * @file */ namespace MediaWiki\Skins\Citizen\Api; use ApiBase; use MediaWiki\MainConfigNames; use MediaWiki\MediaWikiServices; use MediaWiki\Title\Title; use SpecialPage; /** * Based on the MobileFrontend extension * Return the webapp manifest for this wiki * * T282500 * TODO: This should be merged to core */ class ApiWebappManifest extends ApiBase { /* 1 week */ private const CACHE_MAX_AGE = 604800; /** * Execute the requested Api actions. */ public function execute(): void { $services = MediaWikiServices::getInstance(); $config = $this->getConfig(); $resultObj = $this->getResult(); $resultObj->addValue( null, 'dir', $services->getContentLanguage()->getDir() ); $resultObj->addValue( null, 'lang', $config->get( MainConfigNames::LanguageCode ) ); $resultObj->addValue( null, 'name', $config->get( MainConfigNames::Sitename ) ); // Need to set it manually because the default from start_url does not include script namespace // E.g. index.php URLs will be thrown out of the PWA $resultObj->addValue( null, 'scope', $config->get( MainConfigNames::Server ) . '/' ); $resultObj->addValue( null, 'icons', $this->getIcons( $config, $services ) ); $resultObj->addValue( null, 'display', 'standalone' ); $resultObj->addValue( null, 'orientation', 'natural' ); $resultObj->addValue( null, 'start_url', Title::newMainPage()->getLocalURL() ); $resultObj->addValue( null, 'theme_color', $config->get( 'CitizenManifestThemeColor' ) ); $resultObj->addValue( null, 'background_color', $config->get( 'CitizenManifestBackgroundColor' ) ); $resultObj->addValue( null, 'shortcuts', $this->getShortcuts() ); $main = $this->getMain(); $main->setCacheMaxAge( self::CACHE_MAX_AGE ); $main->setCacheMode( 'public' ); } /** * Get icons for manifest * * @param Config $config * @param MediaWikiServices $services * @return array */ private function getIcons( $config, $services ): array { $icons = []; $logos = $config->get( MainConfigNames::Logos ); if ( !$logos ) { return $icons; } $logoKeys = [ '1x', '1.5x', '2x', 'icon', 'svg' ]; foreach ( $logoKeys as $logoKey ) { // Avoid undefined index if ( !isset( $logos[$logoKey] ) ) { continue; } $logoPath = (string)$logos[$logoKey]; $logoUrl = $services->getUrlUtils()->expand( $logoPath, PROTO_CURRENT ) ?? ''; $request = $services->getHttpRequestFactory()->create( $logoUrl, [], __METHOD__ ); $request->execute(); $logoContent = $request->getContent(); if ( !empty( $logoContent ) ) { $logoSize = getimagesizefromstring( $logoContent ); } $icon = [ 'src' => $logoPath ]; if ( isset( $logoSize ) && $logoSize !== false ) { $icon['sizes'] = $logoSize[0] . 'x' . $logoSize[1]; $icon['type'] = $logoSize['mime']; } // Set sizes to any if it is a SVG if ( substr( $logoPath, -3 ) === 'svg' ) { $icon['sizes'] = 'any'; $icon['type'] = 'image/svg+xml'; } $icons[] = $icon; } return $icons; } /** * Get shortcuts for manifest * * @return array */ private function getShortcuts(): array { $specialPages = [ 'Search', 'Randompage', 'RecentChanges' ]; return array_map( static function ( $specialPage ) { $title = SpecialPage::getSafeTitleFor( $specialPage ); return [ 'name' => $title->getBaseText(), 'url' => $title->getLocalURL() ]; }, $specialPages ); } /** * Get the JSON printer * * @return ApiWebappManifestFormatJson */ public function getCustomPrinter() { return new ApiWebappManifestFormatJson( $this->getMain(), 'webmanifest' ); } }