/** * Render the inline difference between two revisions * using InlineDiffEngine */ function showDiff() { $ctx = MobileContext::singleton(); $prevId = $this->prevRev ? $this->prevRev->getId() : 0; $unhide = (bool) $this->getRequest()->getVal('unhide'); $contentHandler = $this->rev->getContentHandler(); $de = $contentHandler->createDifferenceEngine($this->getContext(), $prevId, $this->revId); // HACK: if (get_class($de) == 'DifferenceEngine') { $de = new $this->diffClass($this->getContext(), $prevId, $this->revId, 0, false, $unhide); } else { $de->showDiffPage(); return; } $this->mDiffEngine = $de; $diff = $de->getDiffBody(); if (!$prevId) { $audience = $unhide ? Revision::FOR_THIS_USER : Revision::FOR_PUBLIC; $diff = '<ins>' . nl2br(htmlspecialchars($this->rev->getText($audience))) . '</ins>'; } $warnings = $de->getWarningMessageText(); if ($warnings) { $warnings = MobileUI::warningBox($warnings); } $this->getOutput()->addHtml($warnings . '<div id="mw-mf-minidiff">' . $diff . '</div>'); $prev = $this->rev->getPrevious(); $next = $this->rev->getNext(); if ($prev || $next) { $history = Html::openElement('ul', array('class' => 'hlist revision-history-links')); if ($prev) { $history .= Html::openElement('li') . Html::element('a', array('href' => SpecialPage::getTitleFor('MobileDiff', $prev->getId())->getLocalUrl()), $this->msg('previousdiff')) . Html::closeElement('li'); } if ($next) { $history .= Html::openElement('li') . Html::element('a', array('href' => SpecialPage::getTitleFor('MobileDiff', $next->getId())->getLocalUrl()), $this->msg('nextdiff')) . Html::closeElement('li'); } $history .= Html::closeElement('ul'); $this->getOutput()->addHtml($history); } }
/** * Get the content that needs to be saved in order to undo all revisions * between $undo and $undoafter. Revisions must belong to the same page, * must exist and must not be deleted * @param $undo Revision * @param $undoafter Revision Must be an earlier revision than $undo * @return mixed string on success, false on failure * @since 1.21 * Before we had the Content object, this was done in getUndoText */ public function getUndoContent( Revision $undo, Revision $undoafter = null ) { $handler = $undo->getContentHandler(); return $handler->getUndoContent( $this->getRevision(), $undo, $undoafter ); }
/** * Build a diff display between this and the previous either deleted * or non-deleted edit. * * @param Revision $previousRev * @param Revision $currentRev * @return string HTML */ function showDiff($previousRev, $currentRev) { $diffContext = clone $this->getContext(); $diffContext->setTitle($currentRev->getTitle()); $diffContext->setWikiPage(WikiPage::factory($currentRev->getTitle())); $diffEngine = $currentRev->getContentHandler()->createDifferenceEngine($diffContext); $diffEngine->showDiffStyle(); $formattedDiff = $diffEngine->generateContentDiffBody($previousRev->getContent(Revision::FOR_THIS_USER, $this->getUser()), $currentRev->getContent(Revision::FOR_THIS_USER, $this->getUser())); $formattedDiff = $diffEngine->addHeader($formattedDiff, $this->diffHeader($previousRev, 'o'), $this->diffHeader($currentRev, 'n')); $this->getOutput()->addHTML("<div>{$formattedDiff}</div>\n"); }
/** * @param $title Title * @param $revision Revision * @param $fname string * @return void */ public static function runForTitleInternal(Title $title, Revision $revision, $fname) { wfProfileIn($fname); $content = $revision->getContent(Revision::RAW); if (!$content) { // if there is no content, pretend the content is empty $content = $revision->getContentHandler()->makeEmptyContent(); } // Revision ID must be passed to the parser output to get revision variables correct $parserOutput = $content->getParserOutput($title, $revision->getId(), null, false); $updates = $content->getSecondaryDataUpdates($title, null, false, $parserOutput); DataUpdate::runUpdates($updates); InfoAction::invalidateCache($title); wfProfileOut($fname); }
/** * Extract information from the Revision * * @param Revision $revision * @param object $row Should have a field 'ts_tags' if $this->fld_tags is set * @return array */ protected function extractRevisionInfo(Revision $revision, $row) { $title = $revision->getTitle(); $user = $this->getUser(); $vals = array(); $anyHidden = false; if ($this->fld_ids) { $vals['revid'] = intval($revision->getId()); if (!is_null($revision->getParentId())) { $vals['parentid'] = intval($revision->getParentId()); } } if ($this->fld_flags) { $vals['minor'] = $revision->isMinor(); } if ($this->fld_user || $this->fld_userid) { if ($revision->isDeleted(Revision::DELETED_USER)) { $vals['userhidden'] = true; $anyHidden = true; } if ($revision->userCan(Revision::DELETED_USER, $user)) { if ($this->fld_user) { $vals['user'] = $revision->getUserText(Revision::RAW); } $userid = $revision->getUser(Revision::RAW); if (!$userid) { $vals['anon'] = true; } if ($this->fld_userid) { $vals['userid'] = $userid; } } } if ($this->fld_timestamp) { $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $revision->getTimestamp()); } if ($this->fld_size) { if (!is_null($revision->getSize())) { $vals['size'] = intval($revision->getSize()); } else { $vals['size'] = 0; } } if ($this->fld_sha1) { if ($revision->isDeleted(Revision::DELETED_TEXT)) { $vals['sha1hidden'] = true; $anyHidden = true; } if ($revision->userCan(Revision::DELETED_TEXT, $user)) { if ($revision->getSha1() != '') { $vals['sha1'] = wfBaseConvert($revision->getSha1(), 36, 16, 40); } else { $vals['sha1'] = ''; } } } if ($this->fld_contentmodel) { $vals['contentmodel'] = $revision->getContentModel(); } if ($this->fld_comment || $this->fld_parsedcomment) { if ($revision->isDeleted(Revision::DELETED_COMMENT)) { $vals['commenthidden'] = true; $anyHidden = true; } if ($revision->userCan(Revision::DELETED_COMMENT, $user)) { $comment = $revision->getComment(Revision::RAW); if ($this->fld_comment) { $vals['comment'] = $comment; } if ($this->fld_parsedcomment) { $vals['parsedcomment'] = Linker::formatComment($comment, $title); } } } if ($this->fld_tags) { if ($row->ts_tags) { $tags = explode(',', $row->ts_tags); ApiResult::setIndexedTagName($tags, 'tag'); $vals['tags'] = $tags; } else { $vals['tags'] = array(); } } $content = null; global $wgParser; if ($this->fetchContent) { $content = $revision->getContent(Revision::FOR_THIS_USER, $this->getUser()); // Expand templates after getting section content because // template-added sections don't count and Parser::preprocess() // will have less input if ($content && $this->section !== false) { $content = $content->getSection($this->section, false); if (!$content) { $this->dieUsage("There is no section {$this->section} in r" . $revision->getId(), 'nosuchsection'); } } if ($revision->isDeleted(Revision::DELETED_TEXT)) { $vals['texthidden'] = true; $anyHidden = true; } elseif (!$content) { $vals['textmissing'] = true; } } if ($this->fld_content && $content) { $text = null; if ($this->generateXML) { if ($content->getModel() === CONTENT_MODEL_WIKITEXT) { $t = $content->getNativeData(); # note: don't set $text $wgParser->startExternalParse($title, ParserOptions::newFromContext($this->getContext()), Parser::OT_PREPROCESS); $dom = $wgParser->preprocessToDom($t); if (is_callable(array($dom, 'saveXML'))) { $xml = $dom->saveXML(); } else { $xml = $dom->__toString(); } $vals['parsetree'] = $xml; } else { $vals['badcontentformatforparsetree'] = true; $this->setWarning("Conversion to XML is supported for wikitext only, " . $title->getPrefixedDBkey() . " uses content model " . $content->getModel()); } } if ($this->expandTemplates && !$this->parseContent) { #XXX: implement template expansion for all content types in ContentHandler? if ($content->getModel() === CONTENT_MODEL_WIKITEXT) { $text = $content->getNativeData(); $text = $wgParser->preprocess($text, $title, ParserOptions::newFromContext($this->getContext())); } else { $this->setWarning("Template expansion is supported for wikitext only, " . $title->getPrefixedDBkey() . " uses content model " . $content->getModel()); $vals['badcontentformat'] = true; $text = false; } } if ($this->parseContent) { $po = $content->getParserOutput($title, $revision->getId(), ParserOptions::newFromContext($this->getContext())); $text = $po->getText(); } if ($text === null) { $format = $this->contentFormat ? $this->contentFormat : $content->getDefaultFormat(); $model = $content->getModel(); if (!$content->isSupportedFormat($format)) { $name = $title->getPrefixedDBkey(); $this->setWarning("The requested format {$this->contentFormat} is not " . "supported for content model {$model} used by {$name}"); $vals['badcontentformat'] = true; $text = false; } else { $text = $content->serialize($format); // always include format and model. // Format is needed to deserialize, model is needed to interpret. $vals['contentformat'] = $format; $vals['contentmodel'] = $model; } } if ($text !== false) { ApiResult::setContentValue($vals, 'content', $text); } } if ($content && (!is_null($this->diffto) || !is_null($this->difftotext))) { static $n = 0; // Number of uncached diffs we've had if ($n < $this->getConfig()->get('APIMaxUncachedDiffs')) { $vals['diff'] = array(); $context = new DerivativeContext($this->getContext()); $context->setTitle($title); $handler = $revision->getContentHandler(); if (!is_null($this->difftotext)) { $model = $title->getContentModel(); if ($this->contentFormat && !ContentHandler::getForModelID($model)->isSupportedFormat($this->contentFormat)) { $name = $title->getPrefixedDBkey(); $this->setWarning("The requested format {$this->contentFormat} is not " . "supported for content model {$model} used by {$name}"); $vals['diff']['badcontentformat'] = true; $engine = null; } else { $difftocontent = ContentHandler::makeContent($this->difftotext, $title, $model, $this->contentFormat); $engine = $handler->createDifferenceEngine($context); $engine->setContent($content, $difftocontent); } } else { $engine = $handler->createDifferenceEngine($context, $revision->getID(), $this->diffto); $vals['diff']['from'] = $engine->getOldid(); $vals['diff']['to'] = $engine->getNewid(); } if ($engine) { $difftext = $engine->getDiffBody(); ApiResult::setContentValue($vals['diff'], 'body', $difftext); if (!$engine->wasCacheHit()) { $n++; } } } else { $vals['diff']['notcached'] = true; } } if ($anyHidden && $revision->isDeleted(Revision::DELETED_RESTRICTED)) { $vals['suppressed'] = true; } return $vals; }
/** * Build a diff display between this and the previous either deleted * or non-deleted edit. * * @param Revision $previousRev * @param Revision $currentRev * @return string HTML */ function showDiff($previousRev, $currentRev) { $diffContext = clone $this->getContext(); $diffContext->setTitle($currentRev->getTitle()); $diffContext->setWikiPage(WikiPage::factory($currentRev->getTitle())); $diffEngine = $currentRev->getContentHandler()->createDifferenceEngine($diffContext); $diffEngine->showDiffStyle(); $this->getOutput()->addHTML("<div>" . "<table style='width: 98%;' cellpadding='0' cellspacing='4' class='diff'>" . "<col class='diff-marker' />" . "<col class='diff-content' />" . "<col class='diff-marker' />" . "<col class='diff-content' />" . "<tr>" . "<td colspan='2' style='width: 50%; text-align: center' class='diff-otitle'>" . $this->diffHeader($previousRev, 'o') . "</td>\n" . "<td colspan='2' style='width: 50%; text-align: center' class='diff-ntitle'>" . $this->diffHeader($currentRev, 'n') . "</td>\n" . "</tr>" . $diffEngine->generateContentDiffBody($previousRev->getContent(Revision::FOR_THIS_USER, $this->getUser()), $currentRev->getContent(Revision::FOR_THIS_USER, $this->getUser())) . "</table>" . "</div>\n"); }