When visual editor switches from source mode to visual mode, we need to stash the wikitext. Otherwise, we later lack the proper context to convert the modified HTML back to wikitext. Bug: T321862 Change-Id: Id611e6e022bf8d9d774ca1a3a214220ada713285
116 lines
3 KiB
PHP
116 lines
3 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Edit;
|
|
|
|
use BagOStuff;
|
|
use MediaWiki\Content\IContentHandlerFactory;
|
|
use MediaWiki\Parser\Parsoid\PageBundleJsonTrait;
|
|
use MediaWiki\Parser\Parsoid\ParsoidRenderID;
|
|
|
|
/**
|
|
* @internal
|
|
* @since 1.39
|
|
*/
|
|
class SimpleParsoidOutputStash implements ParsoidOutputStash {
|
|
use PageBundleJsonTrait;
|
|
|
|
/** @var BagOStuff */
|
|
private $bagOfStuff;
|
|
|
|
/** @var int */
|
|
private $duration;
|
|
|
|
/** @var IContentHandlerFactory */
|
|
private $contentHandlerFactory;
|
|
|
|
/**
|
|
* @param IContentHandlerFactory $contentHandlerFactory
|
|
* @param BagOStuff $bagOfStuff storage backend
|
|
* @param int $duration cache duration in seconds
|
|
*/
|
|
public function __construct( IContentHandlerFactory $contentHandlerFactory, BagOStuff $bagOfStuff, int $duration ) {
|
|
$this->bagOfStuff = $bagOfStuff;
|
|
$this->duration = $duration;
|
|
$this->contentHandlerFactory = $contentHandlerFactory;
|
|
}
|
|
|
|
/**
|
|
* Before we stash, we serialize & encode into JSON the relevant
|
|
* parts of the data we need to construct a page bundle in the future.
|
|
*
|
|
* @param ParsoidRenderID $renderId Combination of revision ID and revision's time ID
|
|
* @param SelserContext $selserContext
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function set( ParsoidRenderID $renderId, SelserContext $selserContext ): bool {
|
|
$jsonic = $this->selserContextToJsonArray( $selserContext );
|
|
|
|
$key = $renderId->getKey();
|
|
return $this->bagOfStuff->set( $key, $jsonic, $this->duration );
|
|
}
|
|
|
|
/**
|
|
* This will decode the JSON data and create a page bundle from it
|
|
* if we have something in the stash that matches a given rendering or
|
|
* will just return an empty array if no entry in the stash.
|
|
*
|
|
* @param ParsoidRenderId $renderId
|
|
*
|
|
* @return SelserContext|null
|
|
*/
|
|
public function get( ParsoidRenderId $renderId ): ?SelserContext {
|
|
$jsonic = $this->bagOfStuff->get( $renderId->getKey() ) ?? [];
|
|
|
|
if ( !is_array( $jsonic ) ) {
|
|
// Defend against old stashed data.
|
|
// Only needed for a couple of days after this code has been deployed.
|
|
return null;
|
|
}
|
|
|
|
$selserContext = $this->newSelserContextFromJson( $jsonic );
|
|
return $selserContext ?: null;
|
|
}
|
|
|
|
private function newSelserContextFromJson( array $json ): ?SelserContext {
|
|
if ( !isset( $json['pb'] ) ) {
|
|
return null;
|
|
}
|
|
|
|
$pb = $this->newPageBundleFromJson( $json['pb'] );
|
|
|
|
if ( !$pb ) {
|
|
return null;
|
|
}
|
|
|
|
$revId = (int)$json['revId'];
|
|
|
|
if ( isset( $json['content'] ) ) {
|
|
$contentHandler = $this->contentHandlerFactory->getContentHandler( $json['content']['model'] );
|
|
$content = $contentHandler->unserializeContent( $json['content']['data'] );
|
|
} else {
|
|
$content = null;
|
|
}
|
|
|
|
return new SelserContext( $pb, $revId, $content );
|
|
}
|
|
|
|
private function selserContextToJsonArray( SelserContext $selserContext ): array {
|
|
$json = [
|
|
'revId' => $selserContext->getRevisionID(),
|
|
];
|
|
|
|
$json['pb'] = $this->jsonSerializePageBundle( $selserContext->getPageBundle() );
|
|
|
|
$content = $selserContext->getContent();
|
|
if ( $content ) {
|
|
$json['content'] = [
|
|
'model' => $content->getModel(),
|
|
'data' => $content->serialize()
|
|
];
|
|
}
|
|
|
|
return $json;
|
|
}
|
|
|
|
}
|