/** * Creates and returns a MobileFormatter * * @param MobileContext $context * @param string $html * * @return MobileFormatter */ public static function newFromContext(MobileContext $context, $html) { $mfSpecialCaseMainPage = $context->getMFConfig()->get('MFSpecialCaseMainPage'); $title = $context->getTitle(); $isMainPage = $title->isMainPage() && $mfSpecialCaseMainPage; $isFilePage = $title->inNamespace(NS_FILE); $isSpecialPage = $title->isSpecialPage(); $html = self::wrapHTML($html); $formatter = new MobileFormatter($html, $title); $formatter->enableExpandableSections(!$isMainPage && !$isSpecialPage); $formatter->setIsMainPage($isMainPage); if ($context->getContentTransformations() && !$isFilePage) { $formatter->setRemoveMedia($context->imagesDisabled()); } return $formatter; }
/** * Transforms content to be mobile friendly version. * Filters out various elements and runs the MobileFormatter. * @param OutputPage $out * @param string $mode mobile mode, i.e. stable or beta * * @return string */ public static function DOMParse(OutputPage $out, $text = null, $isBeta = false) { $html = $text ? $text : $out->getHTML(); $context = MobileContext::singleton(); $formatter = MobileFormatter::newFromContext($context, $html); Hooks::run('MobileFrontendBeforeDOM', array($context, $formatter)); $title = $out->getTitle(); $isSpecialPage = $title->isSpecialPage(); $formatter->enableExpandableSections($out->canUseWikiPage() && $out->getWikiPage()->getContentModel() == CONTENT_MODEL_WIKITEXT && array_search($title->getNamespace(), $context->getMFConfig()->get('MFNamespacesWithoutCollapsibleSections')) === false && $context->getRequest()->getText('action', 'view') == 'view'); if ($context->getContentTransformations()) { // Remove images if they're disabled from special pages, but don't transform otherwise $formatter->filterContent(!$isSpecialPage); } $contentHtml = $formatter->getText(); // If the page is a user page which has not been created, then let the // user know about it with pretty graphics and different texts depending // on whether the user is the owner of the page or not. if ($isBeta && $title->inNamespace(NS_USER) && !$title->isSubpage()) { $pageUserId = User::idFromName($title->getText()); if ($pageUserId && !$title->exists()) { $pageUser = User::newFromId($pageUserId); $contentHtml = ExtMobileFrontend::getUserPageContent($out, $pageUser); } } return $contentHtml; }
/** * @dataProvider getHtmlData * * @param $input * @param $expected * @param callable|bool $callback */ public function testHtmlTransform($input, $expected, $callback = false) { $t = Title::newFromText('Mobile'); $input = str_replace("\r", '', $input); // "yay" to Windows! $mf = new MobileFormatter(MobileFormatter::wrapHTML($input), $t); if ($callback) { $callback($mf); } $mf->filterContent(); $html = $mf->getText(); $this->assertEquals(str_replace("\n", '', $expected), str_replace("\n", '', $html)); }
/** * Transforms content to be mobile friendly version. * Filters out various elements and runs the MobileFormatter. * @param OutputPage $out * * @return string */ public static function DOMParse(OutputPage $out) { $html = $out->getHTML(); $context = MobileContext::singleton(); $formatter = MobileFormatter::newFromContext($context, $html); Hooks::run('MobileFrontendBeforeDOM', array($context, $formatter)); $title = $out->getTitle(); $isSpecialPage = $title->isSpecialPage(); $formatter->enableExpandableSections($out->canUseWikiPage() && $out->getWikiPage()->getContentModel() == CONTENT_MODEL_WIKITEXT && array_search($title->getNamespace(), $context->getMFConfig()->get('MFNamespacesWithoutCollapsibleSections')) === false && $context->getRequest()->getText('action', 'view') == 'view'); if ($context->getContentTransformations()) { // Remove images if they're disabled from special pages, but don't transform otherwise $formatter->filterContent(!$isSpecialPage); } $contentHtml = $formatter->getText(); return $contentHtml; }
/** * Get data of requested article. * @param Title $title * @param boolean $noImages * @return array */ private function getData(Title $title, $noImages) { global $wgMemc, $wgUseTidy, $wgMFTidyMobileViewSections, $wgMFMinCachedPageSize, $wgMFSpecialCaseMainPage; $wp = $this->makeWikiPage($title); if ($this->followRedirects && $wp->isRedirect()) { $newTitle = $wp->getRedirectTarget(); if ($newTitle) { $title = $newTitle; $this->getResult()->addValue(null, $this->getModuleName(), array('redirected' => $title->getPrefixedText())); if ($title->getNamespace() < 0) { $this->getResult()->addValue(null, $this->getModuleName(), array('viewable' => 'no')); return array(); } $wp = $this->makeWikiPage($title); } } $latest = $wp->getLatest(); if ($this->file) { $key = wfMemcKey('mf', 'mobileview', self::CACHE_VERSION, $noImages, $latest, $this->noTransform, $this->file->getSha1(), $this->variant); $cacheExpiry = 3600; } else { if (!$latest) { // https://bugzilla.wikimedia.org/show_bug.cgi?id=53378 // Title::exists() above doesn't seem to always catch recently deleted pages $this->dieUsageMsg(array('notanarticle', $title->getPrefixedText())); } $parserOptions = $this->makeParserOptions($wp); $parserCacheKey = ParserCache::singleton()->getKey($wp, $parserOptions); $key = wfMemcKey('mf', 'mobileview', self::CACHE_VERSION, $noImages, $latest, $this->noTransform, $parserCacheKey); } $data = $wgMemc->get($key); if ($data) { wfIncrStats('mobile.view.cache-hit'); return $data; } wfIncrStats('mobile.view.cache-miss'); if ($this->file) { $html = $this->getFilePage($title); } else { $parserOutput = $this->getParserOutput($wp, $parserOptions); $html = $parserOutput->getText(); $cacheExpiry = $parserOutput->getCacheExpiry(); } if (!$this->noTransform) { $mf = new MobileFormatter(MobileFormatter::wrapHTML($html), $title); $mf->setRemoveMedia($noImages); $mf->filterContent(); $mf->setIsMainPage($this->mainPage && $wgMFSpecialCaseMainPage); $html = $mf->getText(); } if ($this->mainPage || $this->file) { $data = array('sections' => array(), 'text' => array($html), 'refsections' => array()); } else { $data = array(); $data['sections'] = $parserOutput->getSections(); $sectionCount = count($data['sections']); for ($i = 0; $i < $sectionCount; $i++) { $data['sections'][$i]['line'] = $title->getPageLanguage()->convert($data['sections'][$i]['line']); } $chunks = preg_split('/<h(?=[1-6]\\b)/i', $html); if (count($chunks) != count($data['sections']) + 1) { wfDebugLog('mobile', __METHOD__ . "(): mismatching number of " . "sections from parser and split on page {$title->getPrefixedText()}, oldid={$latest}"); // We can't be sure about anything here, return all page HTML as one big section $chunks = array($html); $data['sections'] = array(); } $data['text'] = array(); $data['refsections'] = array(); foreach ($chunks as $chunk) { if (count($data['text'])) { $chunk = "<h{$chunk}"; } if ($wgUseTidy && $wgMFTidyMobileViewSections && count($chunks) > 1) { $chunk = MWTidy::tidy($chunk); } if (preg_match('/<ol\\b[^>]*?class="references"/', $chunk)) { $data['refsections'][count($data['text'])] = true; } $data['text'][] = $chunk; } if ($this->usePageImages) { $image = $this->getPageImage($title); if ($image) { $data['image'] = $image->getTitle()->getText(); } } } $data['lastmodified'] = wfTimestamp(TS_ISO_8601, $wp->getTimestamp()); // Page id $data['id'] = $wp->getId(); $user = User::newFromId($wp->getUser()); if (!$user->isAnon()) { $data['lastmodifiedby'] = array('name' => $wp->getUserText(), 'gender' => $user->getOption('gender')); } else { $data['lastmodifiedby'] = null; } $data['revision'] = $title->getLatestRevID(); if (isset($parserOutput)) { $languages = $parserOutput->getLanguageLinks(); $data['languagecount'] = count($languages); $data['displaytitle'] = $parserOutput->getDisplayTitle(); // @fixme: Does no work for some extension properties that get added in LinksUpdate $data['pageprops'] = $parserOutput->getProperties(); } else { $data['languagecount'] = 0; $data['displaytitle'] = $title->getPrefixedText(); $data['pageprops'] = array(); } if ($title->getPageLanguage()->hasVariants()) { $data['hasvariants'] = true; } // Don't store small pages to decrease cache size requirements if (strlen($html) >= $wgMFMinCachedPageSize) { // store for the same time as original parser output $wgMemc->set($key, $data, $cacheExpiry); } return $data; }
} if ($data->type === 'media' && $data->legacyMedia) { ?> <div class='photo-attachment-container'> <?php echo Media::attachmentSocialText($data->legacyMedia->getMediaLink(), true, true); ?> </div> <?php } ?> </div> <div class='bottom-bar'> <div class='event-time'> <?php echo MobileFormatter::formatDateRelative($data->timestamp); ?> </div> <div class='controls'> <?php if ($showComments) { ?> <div data-x2-url='<?php echo $this->createAbsoluteUrl('/profile/mobileViewEvent/id/' . $data->id); ?> ' class='comments'> <div> <?php echo X2Html::fa('comment'); ?>
/** * APIAfterExecute hook handler * @see: https://www.mediawiki.org/wiki/Manual:Hooks/ * @param ApiBase $module * @return bool */ public static function onAPIAfterExecute(ApiBase &$module) { global $wgMFSpecialCaseMainPage; if ($module->getModuleName() == 'parse') { if (defined('ApiResult::META_CONTENT')) { $data = $module->getResult()->getResultData(); } else { $data = $module->getResultData(); } $params = $module->extractRequestParams(); if (isset($data['parse']['text']) && $params['mobileformat']) { $result = $module->getResult(); $result->reset(); $title = Title::newFromText($data['parse']['title']); $text = $data['parse']['text']; if (is_array($text)) { if (defined('ApiResult::META_CONTENT') && isset($text[ApiResult::META_CONTENT])) { $contentKey = $text[ApiResult::META_CONTENT]; } else { $contentKey = '*'; } $html = MobileFormatter::wrapHTML($text[$contentKey]); } else { $html = MobileFormatter::wrapHTML($text); } $mf = new MobileFormatter($html, $title); $mf->setRemoveMedia($params['noimages']); $mf->setIsMainPage($params['mainpage'] && $wgMFSpecialCaseMainPage); $mf->enableExpandableSections(!$params['mainpage']); // HACK: need a nice way to request a TOC- and edit link-free HTML in the first place // FIXME: Should this be .mw-editsection? $mf->remove(array('.toc', 'mw-editsection', '.mw-headline-anchor')); $mf->filterContent(); if (is_array($text)) { $text[$contentKey] = $mf->getText(); } else { $text = $mf->getText(); } $data['parse']['text'] = $text; $result->addValue(null, $module->getModuleName(), $data['parse']); } } return true; }