| Current File : /home/jvzmxxx/wiki1/extensions/Graph/includes/ParserTag.php |
<?php
/**
*
* @license MIT
* @file
*
* @author Dan Andreescu, Yuri Astrakhan, Frédéric Bolduc
*/
namespace Graph;
use FormatJson;
use Html;
use Language;
use Message;
use Parser;
use ParserOptions;
use ParserOutput;
use PPFrame;
use Status;
use Title;
class ParserTag {
/** @var ParserOptions */
private $parserOptions;
/** @var ParserOutput */
private $parserOutput;
/** @var Language */
private $language;
/**
* ParserTag constructor.
* @param Parser $parser
* @param ParserOptions $parserOptions
* @param ParserOutput $parserOutput
*/
public function __construct( Parser $parser, ParserOptions $parserOptions, ParserOutput $parserOutput ) {
$this->parserOptions = $parserOptions;
$this->parserOutput = $parserOutput;
$this->language = $parser->getTargetLanguage();
}
/**
* @param $input
* @param array $args
* @param Parser $parser
* @param PPFrame $frame
* @return string
*/
public static function onGraphTag( $input, array $args, Parser $parser, PPFrame $frame ) {
$tag = new self( $parser, $parser->getOptions(), $parser->getOutput() );
return $tag->buildHtml( $input, $parser->getTitle(), $parser->getRevisionId(), $args );
}
public static function finalizeParserOutput( Parser $parser, $title, ParserOutput $output ) {
if ( $output->getExtensionData( 'graph_specs_broken' ) ) {
$output->addTrackingCategory( 'graph-broken-category', $title );
}
if ( $output->getExtensionData( 'graph_specs_obsolete' ) ) {
$output->addTrackingCategory( 'graph-obsolete-category', $title );
}
$specs = $output->getExtensionData( 'graph_specs' );
if ( $specs !== null ) {
// Store all graph specs as gzip-ed blob in page properties
$ppValue = gzencode( FormatJson::encode( $specs, false, FormatJson::ALL_OK ), 9 );
$output->setProperty( 'graph_specs', $ppValue );
$output->addTrackingCategory( 'graph-tracking-category', $title );
// We can only load one version of vega lib - either 1 or 2
// If the default version is 1, and if any of the graphs need Vega2,
// we treat all graphs as Vega2 and load corresponding libraries.
// All this should go away once we drop Vega1 support.
$liveSpecs = $output->getExtensionData( 'graph_live_specs' );
$interact = $output->getExtensionData( 'graph_interact' );
if ( $parser->getOptions()->getIsPreview() ) {
// Preview generates HTML that is different from normal
$parser->disableCache();
}
if ( $liveSpecs || $interact ) {
$output->addModuleStyles( 'ext.graph.styles' );
if ( $liveSpecs ) {
// Module: ext.graph.vega1, ext.graph.vega2
$output->addModules( 'ext.graph.vega' .
( $output->getExtensionData( 'graph_vega2' ) ? 2 : 1 ) );
$output->addJsConfigVars( 'wgGraphSpecs', $liveSpecs );
} else {
$output->addModules( 'ext.graph.loader' );
}
}
}
}
/**
* @param string $mode
* @param mixed $data
* @param string $hash
* @return array
*/
public static function buildDivAttributes( $mode = '', $data = false, $hash = '' ) {
$attribs = [ 'class' => 'mw-graph' ];
if ( is_object( $data ) ) {
$width = property_exists( $data, 'width' ) && is_int( $data->width ) ? $data->width : 0;
$height =
property_exists( $data, 'height' ) && is_int( $data->height ) ? $data->height : 0;
if ( $width && $height ) {
$attribs['style'] = "min-width:{$width}px;min-height:{$height}px";
}
}
if ( $mode ) {
$attribs['class'] .= ' mw-graph-' . $mode;
}
if ( $hash ) {
$attribs['data-graph-id'] = $hash;
}
return $attribs;
}
private function formatError( Message $msg ) {
$this->parserOutput->setExtensionData( 'graph_specs_broken', true );
$error = $msg->inLanguage( $this->language )->parse();
return "<span class=\"error\">{$error}</span>";
}
private function formatStatus( Status $status ) {
return $this->formatError( $status->getMessage( false, false, $this->language ) );
}
/**
* @param string $jsonText
* @param Title $title
* @param int $revid
* @param array $args
* @return string
*/
public function buildHtml( $jsonText, Title $title, $revid, $args = null ) {
global $wgGraphImgServiceUrl, $wgServerName;
$jsonText = trim( $jsonText );
if ( $jsonText === '' ) {
return $this->formatError( wfMessage( 'graph-error-empty-json' ) );
}
$status = FormatJson::parse( $jsonText, FormatJson::TRY_FIXING | FormatJson::STRIP_COMMENTS );
if ( !$status->isOK() ) {
return $this->formatStatus( $status );
}
$isInteractive = isset( $args['mode'] ) && $args['mode'] === 'interactive';
$graphTitle = isset( $args['title'] ) ? $args['title'] : '';
$data = $status->getValue();
if ( !is_object( $data ) ) {
return $this->formatError( wfMessage( 'graph-error-not-vega' ) );
}
// Figure out which vega version to use
global $wgGraphDefaultVegaVer;
if ( property_exists( $data, 'version' ) && is_numeric( $data->version ) ) {
$data->version = $data->version < 2 ? 1 : 2;
} else {
$data->version = $wgGraphDefaultVegaVer;
}
if ( $data->version === 2 ) {
$this->parserOutput->setExtensionData( 'graph_vega2', true );
} else {
$this->parserOutput->setExtensionData( 'graph_specs_obsolete', true );
}
// Calculate hash and store graph definition in graph_specs extension data
$specs = $this->parserOutput->getExtensionData( 'graph_specs' ) ?: [];
// Make sure that multiple json blobs that only differ in spacing hash the same
$hash = sha1( FormatJson::encode( $data, false, FormatJson::ALL_OK ) );
$specs[$hash] = $data;
$this->parserOutput->setExtensionData( 'graph_specs', $specs );
Store::saveToCache( $hash, $data );
if ( $this->parserOptions->getIsPreview() || !$wgGraphImgServiceUrl ) {
// Always do client-side rendering
$attribs = self::buildDivAttributes( 'always', $data, $hash );
$liveSpecs = $this->parserOutput->getExtensionData( 'graph_live_specs' ) ?: [];
$liveSpecs[$hash] = $data;
$this->parserOutput->setExtensionData( 'graph_live_specs', $liveSpecs );
$html = ''; // will be injected with a <canvas> tag
} else {
// Image from Graphoid
$server = rawurlencode( $wgServerName );
$title = !$title ? '' : rawurlencode( $title->getPrefixedDBkey() );
$revid = rawurlencode( (string)$revid ) ?: '0';
$url = sprintf( $wgGraphImgServiceUrl, $server, $title, $revid, $hash );
$imgAttrs = [
'class' => 'mw-graph-img',
'src' => $url,
];
if ( $graphTitle ) {
// only add alt tag if we have some descriptive text
$imgAttrs['alt'] = $graphTitle;
}
$html = Html::rawElement( 'img', $imgAttrs );
if ( $isInteractive ) {
// Allow image to interactive switchover
$this->parserOutput->setExtensionData( 'graph_interact', true );
$attribs = self::buildDivAttributes( 'interactable', $data, $hash );
// add the overlay title
if ( $graphTitle ) {
$hoverTitle = Html::element( 'div', [ 'class' => 'mw-graph-hover-title' ],
$graphTitle );
} else {
$hoverTitle = '';
}
// Add a "make interactive" button
$button = Html::rawElement( 'div', [ 'class' => 'mw-graph-switch' ],
Html::rawElement( 'i', [ 'class' => 'icon-play' ], '►' ) );
$html .= Html::rawElement( 'div', [
'class' => 'mw-graph-layover',
], $hoverTitle . $button );
} else {
$attribs = self::buildDivAttributes( '', $data );
}
}
return Html::rawElement( 'div', $attribs, $html );
}
}