Page MenuHomeWickedGov Phorge

BannerRenderer.php
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

BannerRenderer.php

<?php
use MediaWiki\Context\IContextSource;
use MediaWiki\Html\Html;
use MediaWiki\MediaWikiServices;
use MediaWiki\ResourceLoader\ResourceLoader;
use MediaWiki\SpecialPage\SpecialPage;
/**
* Produce HTML and JSON output for a given banner and context
*/
class BannerRenderer {
/**
* @var IContextSource
*/
private $context;
/**
* @var Banner
*/
private $banner;
/**
* Campaign in which context the rendering is taking place. Empty during preview.
* @var string
*/
private $campaignName = "";
/**
* Unsaved raw banner content to use for rendering an unsaved preview.
* @var string|null
*/
private $previewContent;
/**
* Associative array of banner message names and values, for rendering an unsaved
* preview.
* @var array|null
*/
private $previewMessages;
/** @var MixinController|null */
private $mixinController = null;
/** @var bool */
private $debug;
/**
* Creates a new renderer for a given banner and context
*
* @param IContextSource $context UI context, including language.
* @param Banner $banner Banner to be rendered.
* @param string|null $campaignName Which campaign we're serving. This is
* substituted in for {{{campaign}}} magic word.
* @param string|null $previewContent Unsaved raw banner content to use for rendering
* an unsaved preview.
* @param array|null $previewMessages Associative array of banner message names and
* and values, for rendering unsaved preview.
* @param bool $debug If false, minify the output.
*/
public function __construct(
IContextSource $context,
Banner $banner,
$campaignName = null,
$previewContent = null,
$previewMessages = null,
$debug = false
) {
$this->context = $context;
$this->banner = $banner;
$this->campaignName = $campaignName;
$this->previewContent = $previewContent;
$this->previewMessages = $previewMessages;
$this->debug = $debug;
$this->mixinController = new MixinController( $this->context, $this->banner->getMixins() );
// FIXME: it should make sense to do this:
// $this->mixinController->registerMagicWord( 'campaign', array( $this, 'getCampaign' ) );
// $this->mixinController->registerMagicWord( 'banner', array( $this, 'getBanner' ) );
}
/**
* Get the edit link for a banner (static version).
*
* @param string $name Banner name.
* @return string Edit URL.
*
* TODO Move the following method somewhere more appropriate.
*/
public static function linkToBanner( $name ) {
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
return $linkRenderer->makeLink(
SpecialPage::getTitleFor( 'CentralNoticeBanners', "edit/{$name}" ),
$name,
[ 'class' => 'cn-banner-title' ]
);
}
/**
* Return a rendered link to the Special:Random banner preview.
*
* @param string $name Banner name
* @return string HTML anchor tag
*
* TODO Move this method somewhere more appropriate.
*/
public static function getPreviewLink( $name ) {
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
// FIXME: Need a reusable way to get a known target language. We want
// to set uselang= so that the banner is rendered using an available
// translation. banner->getPriorityLanguages isn't reliable.
return $linkRenderer->makeKnownLink(
SpecialPage::getTitleFor( 'Randompage' ),
wfMessage( 'centralnotice-live-preview' )->text(),
[ 'class' => 'cn-banner-list-element-label-text' ],
[
'banner' => $name,
// TODO: 'uselang' => $language,
'force' => '1',
]
);
}
/**
* Get the body of the banner, with all transformations applied.
*
* FIXME: "->inLanguage( $context->getLanguage() )" is necessary due to a bug
* in DerivativeContext
*
* @return string HTML fragment for the banner body.
*/
public function toHtml() {
global $wgNoticeUseLanguageConversion;
$parentLang = $lang = $this->context->getLanguage();
if ( $wgNoticeUseLanguageConversion ) {
$parentLang = MediaWikiServices::getInstance()->getLanguageFactory()
->getParentLanguage( $lang->getCode() ) ?? $lang;
}
if ( $this->previewContent !== null ) {
// Preview mode, banner content is ephemeral
// TODO Double-check that this is the correct way to get process as a i18n
// message, and add documentation to the core method.
$bannerHtml = MediaWikiServices::getInstance()->getMessageCache()->transform(
$this->previewContent,
false,
$parentLang
);
} else {
// Normal mode, banner content is stored as message
$bannerKey = $this->banner->getDbKey();
$bannerContentMessage = $this->context->msg( $bannerKey )->inLanguage( $parentLang );
if ( !$bannerContentMessage->exists() ) {
// Translation subsystem failure
throw new RuntimeException(
"Banner message key $bannerKey could not be found in {$parentLang->getCode()}" );
}
$bannerHtml = $bannerContentMessage->text();
}
$bannerHtml .= $this->getResourceLoaderHtml();
$bannerHtml = $this->substituteMagicWords( $bannerHtml );
if ( $wgNoticeUseLanguageConversion ) {
$converter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
->getLanguageConverter( $parentLang );
$variant = $lang->getCode();
if ( $converter->hasVariant( $variant ) ) {
$bannerHtml = $converter->convertTo( $bannerHtml, $variant );
}
}
return $bannerHtml;
}
/**
* Render any preload javascript for this banner
*
* TODO: Remove/refactor. See T225831.
*
* @return string JavaScript code
*/
public function getPreloadJs() {
$code = $this->substituteMagicWords( $this->getPreloadJsRaw() );
// Minify the code, if any.
if ( !$this->debug && $code ) {
$code = ResourceLoader::filter( 'minify-js', $code, [ 'cache' => false ] );
}
return $code;
}
/**
* Unrendered blob of preload javascript snippets
*
* This is only used internally, and will be parsed for magic words
* before use.
*
* TODO: Remove/refactor. See T225831.
*
* @return string JavaScript code
*/
public function getPreloadJsRaw() {
$snippets = $this->mixinController->getPreloadJsSnippets();
return implode( "\n\n", $snippets );
}
/**
* Render any ResourceLoader modules
*
* If the banner includes RL mixins, render the JS (TODO: and CSS) and
* return here.
*
* @return string HTML snippet.
*/
public function getResourceLoaderHtml() {
$modules = $this->mixinController->getResourceLoaderModules();
if ( $modules ) {
// FIXME: Does the RL library already include a helper to do this?
$html = "<!-- " . implode( ", ", array_keys( $modules ) ) . " -->";
$html .= ResourceLoader::makeInlineScript(
Html::encodeJsCall( 'mw.loader.load', array_values( $modules ) )
);
return $html;
}
return "";
}
/**
* Replace magic word placeholders with their value
*
* We rely on $this->renderMagicWord to do the heavy lifting.
*
* @param string $contents Raw contents to be processed.
*
* @return string Rendered contents.
*/
public function substituteMagicWords( $contents ) {
// FIXME The syntax {{{magicword:param1|param2}}} for magic words does not work,
// since it is munged by core before we get it here. It was part of the in-banner
// mixin system, currently unused.
return preg_replace_callback(
'/{{{([^}:]+)(?:[:]([^}]*))?}}}/',
[ $this, 'renderMagicWord' ],
$contents
);
}
/**
* Get a list of magic words provided or dependened upon by this banner
*
* @return array List of magic word names.
*/
public function getMagicWords() {
$words = [ 'banner', 'campaign' ];
$words = array_merge( $words, $this->mixinController->getMagicWords() );
return $words;
}
/**
* Get the value for a magic word
*
* @param array $re_matches Funky PCRE callback param having the form,
* array(
* 0 => full match, ignored,
* 1 => magic word name,
* 2 => optional arguments to the magic word replacement function
* FIXME Doesn't work, unused
* );
*
* @return string HTML fragment with the resulting value.
*/
private function renderMagicWord( $re_matches ) {
$field = $re_matches[1];
if ( $field === 'banner' ) {
return $this->banner->getName();
} elseif ( $field === 'campaign' ) {
return $this->campaignName;
}
// FIXME This doesn't work; part of the unused in-banner mixin system.
$params = [];
if ( isset( $re_matches[2] ) ) {
$params = explode( "|", $re_matches[2] );
}
$value = $this->mixinController->renderMagicWord( $field, $params );
if ( $value !== null ) {
return $value;
}
// Treat anything else as a translatable message
$messageFields = explode( ',', $field, 2 );
if ( isset( $messageFields[ 1 ] ) ) {
// A translatable message from a named banner. String before the comma is the
// banner that defines the message, and the rest is the name of the
// translatable message from that banner.
$bannerMessage = Banner::getMessageFieldForBanner(
trim( $messageFields[ 0 ] ),
trim( $messageFields[ 1 ] )
);
} elseif ( $this->previewMessages !== null &&
array_key_exists( $field, $this->previewMessages ) ) {
// If we're rendering an unsaved preview and the field is provided as an
// unsaved preview message, transform as a messages, sanitize and return that.
// TODO As above, double-check that this is the correct way to get process as
// a i18n message.
return MediaWikiServices::getInstance()->getMessageCache()->transform(
BannerMessage::sanitize( $this->previewMessages[ $field ] ) );
} else {
$bannerMessage = $this->banner->getMessageField( $field );
}
return $bannerMessage->toHtml( $this->context );
}
}

File Metadata

Mime Type
text/x-php
Expires
Fri, Jul 3, 18:54 (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
10/51/7e39373635b8821fc812d40b9974
Default Alt Text
BannerRenderer.php (9 KB)

Event Timeline