| Current File : /home/jvzmxxx/wiki1/extensions/Flow/includes/Formatter/ChangesListFormatter.php |
<?php
namespace Flow\Formatter;
use Flow\Exception\FlowException;
use Flow\Exception\PermissionException;
use Flow\Model\Anchor;
use ChangesList;
use Flow\Model\UUID;
use Flow\Conversion\Utils;
use IContextSource;
use Linker;
class ChangesListFormatter extends AbstractFormatter {
protected function getHistoryType() {
return 'recentchanges';
}
/**
* @param RecentChangesRow $row
* @param IContextSource $ctx
* @param bool $linkOnly
* @return string|false Output line, or false on failure
* @throws FlowException
*/
public function format( RecentChangesRow $row, IContextSource $ctx, $linkOnly = false ) {
$this->serializer->setIncludeHistoryProperties( true );
$this->serializer->setIncludeContent( false );
$data = $this->serializer->formatApi( $row, $ctx, 'recentchanges' );
if ( !$data ) {
return false;
}
if ( $linkOnly ) {
return $this->getTitleLink( $data, $row, $ctx );
}
// The ' . . ' text between elements
$separator = $this->changeSeparator();
$links = array();
$links[] = $this->getDiffAnchor( $data['links'], $ctx );
$links[] = $this->getHistAnchor( $data['links'], $ctx );
$description = $this->formatDescription( $data, $ctx );
$flags = $this->getFlags( $row, $ctx );
return $this->formatAnchorsAsPipeList( $links, $ctx ) .
$separator .
$this->formatFlags( $flags ) .
$this->getTitleLink( $data, $row, $ctx ) .
$ctx->msg( 'semicolon-separator' )->escaped() .
' ' .
$this->formatTimestamp( $data, 'time' ) .
$separator .
ChangesList::showCharacterDifference(
$data['size']['old'],
$data['size']['new'],
$ctx
) .
( Utils::htmlToPlaintext( $description ) ? $separator . $description : '' ) .
$this->getEditSummary( $row, $ctx, $data );
}
/**
* @param RecentChangesRow $row
* @param IContextSource $ctx
* @param array $data
* @return string
*/
public function getEditSummary( RecentChangesRow $row, IContextSource $ctx, array $data ) {
// Build description message, piggybacking on history i18n
$changeType = $data['changeType'];
$actions = $this->permissions->getActions();
$key = $actions->getValue( $changeType, 'history', 'i18n-message' );
// Find specialized message for summary
// i18n messages: flow-rev-message-new-post-recentchanges-summary,
// flow-rev-message-edit-post-recentchanges-summary
$msg = $ctx->msg( $key . '-' . $this->getHistoryType() . '-summary' );
if ( !$msg->exists() ) {
// No summary for this action
return '';
}
$msg = $msg->params( $this->getDescriptionParams( $data, $actions, $changeType ) );
// Below code is inspired by Linker::formatAutocomments
$prefix = $ctx->msg( 'autocomment-prefix' )->inContentLanguage()->escaped();
$link = Linker::link(
$title = $row->workflow->getOwnerTitle(),
$ctx->getLanguage()->getArrow('backwards'),
array(),
array(),
'noclasses'
);
$summary = '<span class="autocomment">' . $msg->text() . '</span>';
// '(' + '' + '←' + summary + ')'
$text = Linker::commentBlock( $prefix . $link . $summary );
// Linker::commentBlock escaped everything, but what we built was safe
// and should not be escaped so let's go back to decoded entities
return htmlspecialchars_decode( $text );
}
/**
* This overrides the default title link to include highlights for the posts
* that have not yet been seen.
*
* @param array $data
* @param FormatterRow $row
* @param IContextSource $ctx
* @return string
*/
protected function getTitleLink( array $data, FormatterRow $row, IContextSource $ctx ) {
if ( !$row instanceof RecentChangesRow ) {
// actually, this should be typehint, but can't because this needs
// to match the parent's more generic typehint
return parent::getTitleLink( $data, $row, $ctx );
}
if ( !isset( $data['links']['topic'] ) || !$data['links']['topic'] instanceof Anchor ) {
// no valid title anchor (probably header entry)
return parent::getTitleLink( $data, $row, $ctx );
}
$watched = $row->recentChange->getAttribute( 'wl_notificationtimestamp' );
if ( is_bool( $watched ) ) {
// RC & watchlist share most code; the latter is unaware of when
// something was watched though, so we'll ignore that here
return parent::getTitleLink( $data, $row, $ctx );
}
if ( $watched === null ) {
// there is no data for unread posts - they've all been seen
return parent::getTitleLink( $data, $row, $ctx );
}
// get comparison UUID corresponding to this last watched timestamp
$uuid = UUID::getComparisonUUID( $watched );
// add highlight details to anchor
/** @var Anchor $anchor */
$anchor = clone $data['links']['topic'];
$anchor->query['fromnotif'] = '1';
$anchor->fragment = '#flow-post-' . $uuid->getAlphadecimal();
$data['links']['topic'] = $anchor;
// now pass it on to parent with the new, updated, link ;)
return parent::getTitleLink( $data, $row, $ctx );
}
/**
* @param RecentChangesRow $row
* @param IContextSource $ctx
* @return string
* @throws PermissionException
*/
public function getTimestampLink( $row, $ctx ) {
$data = $this->serializer->formatApi( $row, $ctx, 'recentchanges' );
if ( $data === false ) {
throw new PermissionException( 'Insufficient permissions for ' . $row->revision->getRevisionId()->getAlphadecimal() );
}
return $this->formatTimestamp( $data, 'time' );
}
/**
* @param RecentChangesRow $row
* @param IContextSource $ctx
* @param array $block
* @param array $links
* @return array|false Links array, or false on failure
* @throws FlowException
* @throws \Flow\Exception\InvalidInputException
*/
public function getLogTextLinks( RecentChangesRow $row, IContextSource $ctx, array $block, array $links = array() ) {
$data = $this->serializer->formatApi( $row, $ctx, 'recentchanges' );
if ( !$data ) {
return false;
}
$old = unserialize( $block[count( $block ) - 1]->mAttribs['rc_params'] );
$oldId = $old ? UUID::create( $old['flow-workflow-change']['revision'] ) : $row->revision->getRevisionId();
if ( isset( $data['links']['topic'] ) ) {
// add highlight details to anchor
/** @var Anchor $anchor */
$anchor = clone $data['links']['topic'];
$anchor->query['fromnotif'] = '1';
$anchor->fragment = '#flow-post-' . $oldId->getAlphadecimal();
} elseif ( isset( $data['links']['workflow'] ) ) {
$anchor = $data['links']['workflow'];
} else {
// this will be caught and logged by the RC hook, it will not fatal the page.
throw new FlowException( "No anchor available for revision $oldId" );
}
$changes = count( $block );
// link text: "n changes"
$text = $ctx->msg( 'nchanges' )->numParams( $changes )->escaped();
// override total changes link
$links['total-changes'] = $anchor->toHtml( $text );
return $links;
}
/**
* @param RecentChangesRow $row
* @param IContextSource $ctx
* @return array
*/
public function getFlags( RecentChangesRow $row, IContextSource $ctx )
{
return array(
'newpage' => $row->isFirstReply && $row->revision->isFirstRevision(),
'minor' => false,
'unpatrolled' => ChangesList::isUnpatrolled( $row->recentChange, $ctx->getUser() ),
'bot' => false,
);
}
/**
* @param array $flags
* @return string
*/
protected function formatFlags( $flags ) {
$flagKeys = array_keys( array_filter( $flags ) );
if ( $flagKeys ) {
$formattedFlags = array_map( 'ChangesList::flag', $flagKeys );
return implode( ' ', $formattedFlags ) . ' ';
}
return '';
}
}