/** * Generates HTML for the uploads page for the passed user. * * @param User $user * @return string */ public function getUserUploadsPageHtml(User $user) { $uploadCount = $this->getUserUploadCount($user->getName()); $mobileContext = MobileContext::singleton(); $html = ''; $attrs = array(); if ($uploadCount !== false) { $threshold = $this->getUploadCountThreshold(); // FIXME: Use Html class? $html .= '<div class="content">'; if ($mobileContext->userCanUpload()) { $html .= '<div class="ctaUploadPhoto"></div>'; } if ($uploadCount > $threshold) { $msg = $this->msg('mobile-frontend-photo-upload-user-count-over-limit')->text(); } else { $msg = $this->msg('mobile-frontend-photo-upload-user-count')->numParams($uploadCount)->parse(); if ($uploadCount === 0) { $attrs = array('style' => 'display:none'); } } $html .= Html::openElement('h2', $attrs) . $msg . Html::closeElement('h2'); $html .= '</div>'; } return $html; }
/** * Updates the aa_lastlogin value for the specified user * * @param User $user the user that just logged in * * @return bool return True to continue processing hooks */ static function updateLastLogin(User $user) { if (wfReadOnly()) { return true; } $now = time(); $db = wfGetDB(DB_MASTER); $method = __METHOD__; $requestMethod = self::ACCESS_METHOD_DEFAULT; if (class_exists("MobileContext") && MobileContext::singleton()->shouldDisplayMobileView()) { $requestMethod = self::ACCESS_METHOD_MOBILE; } $db->onTransactionIdle(function () use($user, $requestMethod, $now, $db, $method) { if ($db->getType() === 'mysql') { // MySQL-specific implementation $db->query("INSERT INTO " . $db->tableName('accountaudit_login') . "( aa_user, aa_method, aa_lastlogin ) VALUES (" . $db->addQuotes($user->getId()) . ", " . $db->addQuotes($requestMethod) . ", " . $db->addQuotes($db->timestamp($now)) . ") ON DUPLICATE KEY UPDATE aa_lastlogin = " . $db->addQuotes($db->timestamp($now)), $method); } else { $db->update('accountaudit_login', array('aa_lastlogin' => $db->timestamp($now)), array('aa_user' => $user->getId(), 'aa_method' => $requestMethod), $method); if ($db->affectedRows() == 0) { // no row existed for that user, method $db->insert('accountaudit_login', array('aa_user' => $user->getId(), 'aa_method' => $requestMethod, 'aa_lastlogin' => $db->timestamp($now)), $method, array('IGNORE')); } } }); // always return true, this should be a non-blocking hook on failure return true; }
/** * Render the special page and redirect the user to the editor (if page exists) * @param string $subpage The name of the page to edit */ public function executeWhenAvailable($subpage) { if (!is_string($subpage)) { $this->showPageNotFound(); return; } else { $title = Title::newFromText($subpage); if (is_null($title)) { $this->showPageNotFound(); return; } } $data = $this->getRequest()->getValues(); unset($data['title']); // Remove the title of the special page $section = (int) $this->getRequest()->getVal('section', 0); $output = $this->getOutput(); $output->addModules('mobile.special.mobileeditor.scripts'); $output->setPageTitle($this->msg('mobile-frontend-editor-redirect-title')->text()); $context = MobileContext::singleton(); $articleUrl = $context->getMobileUrl($title->getFullURL($data)); $targetUrl = $articleUrl . '#/editor/' . $section; $html = Html::openElement('div', array('id' => 'mw-mf-editor', 'data-targeturl' => $targetUrl)) . Html::openElement('noscript') . MobileUI::errorBox($this->msg('mobile-frontend-editor-unavailable')->text()) . Html::openElement('p') . Html::element('a', array('href' => $title->getLocalUrl()), $this->msg('returnto', $title->getText())->text()) . Html::closeElement('noscript') . Html::closeElement('div'); // #mw-mf-editorunavailable $output->addHTML($html); }
/** * Render the navigation menu * @param string $par never used */ public function executeWhenAvailable($par = '') { $this->setHeaders(); $out = $this->getOutput(); $out->setPageTitle(wfMessage('mobile-frontend-main-menu-page-title')->text()); if (!MobileContext::singleton()->isAlphaGroupMember()) { $out->setProperty('bodyClassName', 'navigation-enabled navigation-full-screen'); } }
/** * @dataProvider redirectFromDesktopDiffProvider */ public function testRedirectFromDesktopDiff(array $query, $expected) { foreach ($query as $k => $v) { MobileContext::singleton()->getRequest()->setVal($k, $v); $this->unsetReqVals[] = $k; } if ($expected) { $expected = Title::newFromText($expected)->getLocalURL(); } $redirectUrl = MockSpecialMobileDiff::getMobileUrlFromDesktop(); $this->assertEquals($expected, $redirectUrl); }
/** * Generate user page content for non-existent user pages * * @param OutputPage $output * @param User $pageUser owner of the user page * @return string */ public static function getUserPageContent($output, $pageUser) { $context = MobileContext::singleton(); $pageUsername = $pageUser->getName(); // Is the current user viewing their own page? $isCurrentUser = $output->getUser()->getName() === $pageUsername; $data['ctaHeading'] = $isCurrentUser ? $context->msg('mobile-frontend-user-page-no-owner-page-yet')->text() : $context->msg('mobile-frontend-user-page-no-page-yet', $pageUsername)->parse(); $data['ctaDescription'] = $isCurrentUser ? $context->msg('mobile-frontend-user-page-describe-yourself', $context->msg('mobile-frontend-user-page-describe-yourself-editors')->text())->text() : $context->msg('mobile-frontend-user-page-desired-action', $pageUsername)->parse(); $data['createPageLinkLabel'] = $isCurrentUser ? $context->msg('mobile-frontend-user-page-create-owner-page-link-label')->text() : $context->msg('mobile-frontend-user-page-create-user-page-link-label', $pageUser->getUserPage()->getBaseTitle())->parse(); $data['createPageLinkAdditionalClasses'] = $isCurrentUser ? 'mw-ui-button' : ''; $templateParser = new TemplateParser(__DIR__); return $templateParser->processTemplate('user_page_cta', $data); }
/** * Get CSS classes for icons * @param string $iconName * @param string $iconType element or before * @param string $additionalClassNames additional class names you want to associate * with the iconed element * @return string class name for use with HTML element */ public static function iconClass($iconName, $iconType = 'element', $additionalClassNames = '') { $ctx = MobileContext::singleton(); if ($ctx->isBetaGroupMember()) { $base = 'mw-ui-icon'; $modifiers = 'mw-ui-icon-' . $iconType; $modifiers .= ' mw-ui-icon-' . $iconName; } else { $base = 'icon'; $modifiers = $iconType === 'before' ? 'icon-text' : ''; $modifiers .= ' icon-' . $iconName; } return $base . ' ' . $modifiers . ' ' . $additionalClassNames; }
/** * 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; }
/** * Checks the availability of the special page in actual mode and display the page, if available * @param string $subPage parameter submitted as "subpage" */ public function execute($subPage) { $ctx = MobileContext::singleton(); $this->config = $ctx->getMFConfig(); $this->getOutput()->setProperty('desktopUrl', $this->getDesktopUrl($subPage)); if (!$ctx->shouldDisplayMobileView() && !$this->hasDesktopVersion) { $this->renderUnavailableBanner($this->msg('mobile-frontend-requires-mobile')); } elseif ($this->mode !== 'stable') { if ($this->mode === 'beta' && !$ctx->isBetaGroupMember()) { $this->renderUnavailableBanner($this->msg('mobile-frontend-requires-optin')->parse()); } else { $this->executeWhenAvailable($subPage); } } else { $this->executeWhenAvailable($subPage); } }
/** * Returns a count of the most recent uploads to $wgMFPhotoUploadWiki since * a given timestamp, not exceeding LIMIT. * * @param int $fromDate Time to measure from * @return int the amount of edits */ public function countRecentUploads($fromDate) { $mfPhotoUploadWiki = MobileContext::singleton()->getMFConfig()->get('MFPhotoUploadWiki'); global $wgConf; if (!$mfPhotoUploadWiki) { $dbr = wfGetDB(DB_SLAVE); } elseif ($mfPhotoUploadWiki && !in_array($mfPhotoUploadWiki, $wgConf->getLocalDatabases())) { // early return if the database is invalid return false; } else { $dbr = wfGetDB(DB_SLAVE, array(), $mfPhotoUploadWiki); } $where = array('img_user_text' => $this->user->getName()); $where[] = 'img_timestamp > ' . $dbr->addQuotes($dbr->timestamp($fromDate)); $constraints = array('LIMIT' => self::LIMIT + 1); $result = $dbr->selectRowCount('image', 'img_timestamp', $where, __METHOD__, $constraints); return $result; }
/** * APIAfterExecute hook handler * @see: https://www.mediawiki.org/wiki/Manual:Hooks/ * @param ApiBase $module * @return bool */ public static function onAPIAfterExecute(ApiBase &$module) { $mfSpecialCaseMainPage = MobileContext::singleton()->getMFConfig()->get('MFSpecialCaseMainPage'); 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'] && $mfSpecialCaseMainPage); $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; }
/** * @dataProvider providerShowRedLinks */ public function testRedLinks($showRedLinks, $showRedLinksAnon, $username, $expected) { // set config variables, which we test here $values = array('wgMFShowRedLinks' => $showRedLinks, 'wgMFShowRedLinksAnon' => $showRedLinksAnon, 'wgMFEnableBeta' => true); $this->setMwGlobals($values); // create our specific user object $user = User::newFromName($username); $user->load(); // create a new RequestContext for this test case and set User and title $context = new RequestContext(); $context->setUser($user); $context->setTitle(Title::newFromText('Main_page')); // create SkinMinerva to test $skin = $this->getSkin(); $skin->setContext($context); // set the fake mobile mode MobileContext::singleton()->setMobileMode($this->getMode()); // test now $vars = $skin->getSkinConfigVariables(); $this->assertEquals($expected, $vars['wgMFShowRedLinks']); }
/** * Check, if context modules aren't arrays. They will be added as an array with modules to * to load, which doesn't allow arrays as values. */ public function testGetContextSpecificModules() { // try to cover all possible modules (maybe extent, if other modules added) $values = array('wgMFEnableBeta' => true); $this->setMwGlobals($values); // UTSysop will be a logged in user $user = User::newFromName('UTSysop'); $user->load(); // create a new RequestContext for this test case and set User and title $context = new RequestContext(); $context->setUser($user); // UTPage is an existing page in the main namespace $context->setTitle(Title::newFromText('UTPage')); MobileContext::singleton()->setMobileMode('alpha'); $skin = $this->getSkin(); $skin->setContext($context); $modules = $skin->getContextSpecificModules(); foreach ($modules as $module) { $this->assertFalse(is_array($module), 'Context specific modules can\'t be arrays.'); } }
/** * @param $user object: The User object that was created. * @param $byEmail boolean The form has a [By e-mail] button. * @return bool True */ public static function onAddNewAccount($user, $byEmail) { global $wgRequest, $wgUser; $userId = $user->getId(); $creatorUserId = $wgUser->getId(); // MediaWiki allows existing users to create accounts on behalf // of others. In such cases the ID of the newly-created user and // the ID of the user making this web request are different. $isSelfMade = $userId && $userId === $creatorUserId; $displayMobile = class_exists('MobileContext') && MobileContext::singleton()->shouldDisplayMobileView(); $event = array('token' => $wgRequest->getCookie('mediaWiki.user.id', '', ''), 'userId' => $userId, 'userName' => $user->getName(), 'isSelfMade' => $isSelfMade, 'userBuckets' => $wgRequest->getCookie('userbuckets', '', ''), 'displayMobile' => $displayMobile); $returnTo = $wgRequest->getVal('returnto'); if ($returnTo !== null) { $event['returnTo'] = $returnTo; } $returnToQuery = $wgRequest->getVal('returntoquery'); if ($returnToQuery !== null) { $event['returnToQuery'] = $returnToQuery; } efLogServerSideEvent('ServerSideAccountCreation', 5233795, $event); return true; }
/** * Creates a new set of object for the actual test context, including a new * outputpage and skintemplate. * * @param string $mode The mode for the test cases (desktop, mobile) * @return array Array of objects, including MobileContext (context), * SkinTemplate (sk) and OutputPage (out) */ protected function getContextSetup($mode, $mfXAnalyticsItems) { // Create a new MobileContext object for this test MobileContext::setInstance(null); // create a new instance of MobileContext $context = MobileContext::singleton(); // create a DerivativeContext to use in MobileContext later $mainContext = new DerivativeContext(RequestContext::getMain()); // create a new, empty OutputPage $out = new OutputPage($context); // create a new, empty SkinTemplate $sk = new SkinTemplate(); // create a new Title (main page) $title = Title::newMainPage(); // create a FauxRequest to use instead of a WebRequest object (FauxRequest forces // the creation of a FauxResponse, which allows to investigate sent header values) $request = new FauxRequest(); // set the new request object to the context $mainContext->setRequest($request); // set the main page title to the context $mainContext->setTitle($title); // set the context to the SkinTemplate $sk->setContext($mainContext); // set the OutputPage to the context $mainContext->setOutput($out); // set the DerivativeContext as a base to MobileContext $context->setContext($mainContext); // set the mode to MobileContext $context->setUseFormat($mode); // if there are any XAnalytics items, add them foreach ($mfXAnalyticsItems as $key => $val) { $context->addAnalyticsLogItem($key, $val); } // set the newly created MobileContext object as the current instance to use MobileContext::setInstance($context); // return the stuff return array('out' => $out, 'sk' => $sk, 'context' => $context); }
/** * Returns an array of languages that the page is available in * @return array */ private function getLanguages() { $api = new ApiMain(new DerivativeRequest($this->getRequest(), array('action' => 'query', 'prop' => 'langlinks', 'llprop' => 'url', 'lllimit' => 'max', 'titles' => $this->title->getPrefixedText()))); $api->execute(); if (defined('ApiResult::META_CONTENT')) { $data = (array) $api->getResult()->getResultData(array('query', 'pages'), array('Strip' => 'all')); } else { $data = $api->getResult()->getData(); // Paranoia if (!isset($data['query']['pages'])) { return array(); } $data = $data['query']['pages']; } // Silly strict php $pages = array_values($data); $page = array_shift($pages); if (isset($page['langlinks'])) { // Set the name of each lanugage based on the system list of language names $languageMap = Language::fetchLanguageNames(); $languages = $page['langlinks']; foreach ($page['langlinks'] as $code => $langObject) { if (!isset($languageMap[$langObject['lang']])) { // Bug T93500: DB might still have preantiquated rows with bogus languages unset($languages[$code]); continue; } $langObject['langname'] = $languageMap[$langObject['lang']]; $langObject['url'] = MobileContext::singleton()->getMobileUrl($langObject['url']); $languages[$code] = $langObject; } return $languages; } else { // No langlinks available return array(); } }
/** * Returns HTML of license link or empty string * For example: * "<a title="Wikipedia:Copyright" href="/index.php/Wikipedia:Copyright">CC BY</a>" * * @param string $context The context in which the license link appears, e.g. footer, * editor, talk, or upload. * @param array $attribs An associative array of extra HTML attributes to add to the link * @return string */ public static function getLicense($context, $attribs = array()) { $config = MobileContext::singleton()->getConfig(); $rightsPage = $config->get('RightsPage'); $rightsUrl = $config->get('RightsUrl'); $rightsText = $config->get('RightsText'); // Construct the link to the licensing terms if ($rightsText) { // Use shorter text for some common licensing strings. See Installer.i18n.php // for the currently offered strings. Unfortunately, there is no good way to // comprehensively support localized licensing strings since the license (as // stored in LocalSetttings.php) is just freeform text, not an i18n key. $commonLicenses = array('Creative Commons Attribution-Share Alike 3.0' => 'CC BY-SA 3.0', 'Creative Commons Attribution Share Alike' => 'CC BY-SA', 'Creative Commons Attribution 3.0' => 'CC BY 3.0', 'Creative Commons Attribution 2.5' => 'CC BY 2.5', 'Creative Commons Attribution' => 'CC BY', 'Creative Commons Attribution Non-Commercial Share Alike' => 'CC BY-NC-SA', 'Creative Commons Zero (Public Domain)' => 'CC0 (Public Domain)', 'GNU Free Documentation License 1.3 or later' => 'GFDL 1.3 or later'); if (isset($commonLicenses[$rightsText])) { $rightsText = $commonLicenses[$rightsText]; } if ($rightsPage) { $title = Title::newFromText($rightsPage); $link = Linker::linkKnown($title, $rightsText, $attribs); } elseif ($rightsUrl) { $link = Linker::makeExternalLink($rightsUrl, $rightsText, true, '', $attribs); } else { $link = $rightsText; } } else { $link = ''; } // Allow other extensions (for example, WikimediaMessages) to override Hooks::run('MobileLicenseLink', array(&$link, $context, $attribs)); // for plural support we need the info, if there is one or more licenses used in the license text // this check if very simple and works on the base, that more than one license will // use "and" as a connective // 1 - no plural // 2 - plural $delimiterMsg = wfMessage('and'); // check, if "and" isn't disabled and exists in site language $isPlural = !$delimiterMsg->isDisabled() && strpos($rightsText, $delimiterMsg->text()) === false ? 1 : 2; return array('link' => $link, 'plural' => $isPlural); }
/** * Get the URL of this special page * @param string|null $option Subpage string, or false to not use a subpage * @param Title $returnTo Destination to returnto after successfully action on the page returned * @param boolean $fullUrl Whether to get the local url, or the full url * * @return string */ public static function getURL($option, Title $returnTo = null, $fullUrl = false) { $t = SpecialPage::getTitleFor('MobileOptions', $option); $params = array(); if ($returnTo) { $params['returnto'] = $returnTo->getPrefixedText(); } if ($fullUrl) { return MobileContext::singleton()->getMobileUrl($t->getFullURL($params)); } else { return $t->getLocalURL($params); } }
/** * Get the HTML needed to show if a user doesn't watch any page, show information * how to watch pages where no pages have been watched. * @param boolean $feed Render as feed (true) or list (false) view? * @param Language $lang The language of the current mode * @return string */ public static function getEmptyListHtml($feed, $lang) { $dir = $lang->isRTL() ? 'rtl' : 'ltr'; $imgUrl = MobileContext::singleton()->getConfig()->get('ExtensionAssetsPath') . "/MobileFrontend/images/emptywatchlist-page-actions-{$dir}.png"; if ($feed) { $msg = Html::element('p', null, wfMessage('mobile-frontend-watchlist-feed-empty')->plain()); } else { $msg = Html::element('p', null, wfMessage('mobile-frontend-watchlist-a-z-empty-howto')->plain()); $msg .= Html::element('img', array('src' => $imgUrl, 'alt' => wfMessage('mobile-frontend-watchlist-a-z-empty-howto-alt')->plain())); } return Html::openElement('div', array('class' => 'info empty-page')) . $msg . Html::element('a', array('class' => 'button', 'href' => Title::newMainPage()->getLocalUrl()), wfMessage('mobile-frontend-watchlist-back-home')->plain()) . Html::closeElement('div'); }
/** * Returns an instance of detection class, overridable by extensions * @return IDeviceDetector */ public static function factory() { $deviceDetectionClass = MobileContext::singleton()->getMFConfig()->get('DeviceDetectionClass'); static $instance = null; if (!$instance) { $instance = new $deviceDetectionClass(); } return $instance; }
/** * Returns HTML of license link or empty string * For example: * "<a title="Wikipedia:Copyright" href="/index.php/Wikipedia:Copyright">CC BY</a>" * * @param string $context The context in which the license link appears, e.g. footer, * editor, talk, or upload. * @param array $attribs An associative array of extra HTML attributes to add to the link * @return string */ public static function getLicenseLink($context, $attribs = array()) { $config = MobileContext::singleton()->getConfig(); $rightsPage = $config->get('RightsPage'); $rightsUrl = $config->get('RightsUrl'); $rightsText = $config->get('RightsText'); // Construct the link to the licensing terms if ($rightsText) { // Use shorter text for some common licensing strings. See Installer.i18n.php // for the currently offered strings. Unfortunately, there is no good way to // comprehensively support localized licensing strings since the license (as // stored in LocalSetttings.php) is just freeform text, not an i18n key. $commonLicenses = array('Creative Commons Attribution-Share Alike 3.0' => 'CC BY-SA 3.0', 'Creative Commons Attribution Share Alike' => 'CC BY-SA', 'Creative Commons Attribution 3.0' => 'CC BY 3.0', 'Creative Commons Attribution 2.5' => 'CC BY 2.5', 'Creative Commons Attribution' => 'CC BY', 'Creative Commons Attribution Non-Commercial Share Alike' => 'CC BY-NC-SA', 'Creative Commons Zero (Public Domain)' => 'CC0 (Public Domain)', 'GNU Free Documentation License 1.3 or later' => 'GFDL 1.3 or later'); if (isset($commonLicenses[$rightsText])) { $rightsText = $commonLicenses[$rightsText]; } if ($rightsPage) { $title = Title::newFromText($rightsPage); $link = Linker::linkKnown($title, $rightsText, $attribs); } elseif ($rightsUrl) { $link = Linker::makeExternalLink($rightsUrl, $rightsText, true, '', $attribs); } else { $link = $rightsText; } } else { $link = ''; } // Allow other extensions (for example, WikimediaMessages) to override Hooks::run('MobileLicenseLink', array(&$link, $context, $attribs)); return $link; }
/** * HTMLFileCache::useFileCache hook handler * Disables file caching for mobile pageviews * @see https://www.mediawiki.org/wiki/Manual:Hooks/HTMLFileCache::useFileCache * * @return bool */ public static function onHTMLFileCache_useFileCache() { return !MobileContext::singleton()->shouldDisplayMobileView(); }
/** * Returns the site name for the footer, either as a text or <img> tag * @param boolean $withPossibleTrademark If true and a trademark symbol is specified * by $wgMFTrademarkSitename, append that trademark symbol to the sitename/logo. * This param exists so that the trademark symbol can be appended in some * contexts, for example, the footer, but not in others. See bug T95007. * @return string */ public static function getSitename($withPossibleTrademark = false) { $config = MobileContext::singleton()->getMFConfig(); $customLogos = $config->get('MFCustomLogos'); $trademarkSymbol = $config->get('MFTrademarkSitename'); $suffix = ''; $footerSitename = wfMessage('mobile-frontend-footer-sitename')->text(); // Add a trademark symbol if needed if ($withPossibleTrademark) { // Registered trademark if ($trademarkSymbol === 'registered') { $suffix = Html::element('sup', array(), '®'); // Unregistered (or unspecified) trademark } elseif ($trademarkSymbol) { $suffix = Html::element('sup', array(), '™'); } } // If there's a custom site logo, use that instead of text if (isset($customLogos['copyright'])) { $attributes = array('src' => $customLogos['copyright'], 'alt' => $footerSitename . $suffix); if (isset($customLogos['copyright-height'])) { $attributes['height'] = $customLogos['copyright-height']; } if (isset($customLogos['copyright-width'])) { $attributes['width'] = $customLogos['copyright-width']; } $sitename = Html::element('img', $attributes); } else { $sitename = $footerSitename; } return $sitename . $suffix; }
/** * Display Mobile Frontend specific logo over login form. */ protected function getLogoHtml() { $mfLogo = MobileContext::singleton()->getMFConfig()->get('MobileFrontendLogo'); if (!$mfLogo) { return ''; } return '<div class="watermark">' . Html::element('img', array('src' => $mfLogo, 'alt' => '')) . '</div>'; }
/** * Removes content inappropriate for mobile devices * @param bool $removeDefaults Whether default settings at $wgMFRemovableClasses should be used * @return array */ public function filterContent($removeDefaults = true) { $mfRemovableClasses = MobileContext::singleton()->getMFConfig()->get('MFRemovableClasses'); if ($removeDefaults) { $this->remove($mfRemovableClasses['base']); $this->remove($mfRemovableClasses['HTML']); // @todo: Migrate this variable } if ($this->removeMedia) { $this->doRemoveImages(); } return parent::filterContent(); }
/** * Renders the view/edit (normal) mode of the watchlist. */ protected function executeViewEditWatchlist() { $ns = NS_MAIN; $html = ''; $total = 0; $images = array(); $watchlist = $this->getWatchlistInfo(); if (isset($watchlist[$ns])) { $allPages = $watchlist[$ns]; $from = $this->getNextPage($allPages); $allPages = $this->getPagesToDisplay($allPages); } else { $allPages = array(); $from = false; } // Begin rendering of watchlist. $watchlist = array($ns => $allPages); if (!MobileContext::singleton()->imagesDisabled()) { Hooks::run('SpecialMobileEditWatchlist::images', array($this->getContext(), &$watchlist, &$images)); } // create list of pages $mobilePages = new MobileCollection(); $pageKeys = array_keys($watchlist[$ns]); foreach ($pageKeys as $dbkey) { if (isset($images[$ns][$dbkey])) { $page = new MobilePage(Title::makeTitleSafe($ns, $dbkey), wfFindFile($images[$ns][$dbkey])); } else { $page = new MobilePage(Title::makeTitleSafe($ns, $dbkey)); } $mobilePages->add($page); } if (count($mobilePages) === 0) { $html = SpecialMobileWatchlist::getEmptyListHtml(false, $this->getLanguage()); } else { $html = $this->getViewHtml($mobilePages); } if ($from) { // show more link if there are more items to show $qs = array('from' => $from); $html .= Html::element('a', array('class' => MobileUI::anchorClass('progressive', 'more'), 'href' => SpecialPage::getTitleFor('EditWatchlist')->getLocalURL($qs)), $this->msg('mobile-frontend-watchlist-more')); } $out = $this->getOutput(); $out->addHtml($html); $out->addModules('skins.minerva.special.watchlist.scripts'); $out->addModuleStyles(array('skins.minerva.special.styles', 'skins.minerva.special.watchlist.styles', 'mobile.pagelist.styles', 'mobile.pagesummary.styles', 'mobile.special.pagefeed.styles')); }
/** * Get the url for the mobile diff special page to use in Desktop footer * @return boolean|string Return URL or false when revision id's not set */ public static function getMobileUrlFromDesktop() { $req = MobileContext::singleton()->getRequest(); $rev2 = $req->getText('diff'); $rev1 = $req->getText('oldid'); if ($rev1 == 'prev' || $rev1 == 'next') { // Actually, both do the same, WTF $rev1 = ''; } // redirect requests to the diff page to mobile view if (!$rev2) { if ($rev1) { $rev2 = $rev1; $rev1 = ''; } else { return false; } } if ($rev1) { $rev = static::getRevision($rev1); if ($rev) { // the diff parameter could be the string prev or next - deal with these cases if ($rev2 === 'prev') { $prev = $rev->getPrevious(); // yes this is confusing - this is how it works arrgghh $rev2 = $rev1; $rev1 = $prev ? $prev->getId() : ''; } elseif ($rev2 === 'next') { $next = $rev->getNext(); $rev2 = $next ? $next->getId() : ''; } else { $rev2 = static::getRevision($rev2); $rev2 = $rev2 ? $rev2->getId() : ''; } } else { $rev2 = ''; } } if ($rev2) { $subpage = $rev1 ? $rev1 . '...' . $rev2 : $rev2; $title = SpecialPage::getTitleFor('MobileDiff', $subpage); return $title->getLocalURL(); } return false; }
/** * Build the HTML containing the 1x1 images * @return string */ static function getEdgeLoginHTML() { global $wgCentralAuthLoginWiki, $wgCentralAuthAutoLoginWikis; // Put images inside a div so that other code that manipulates page content can // explicitly ignore them. $html = Xml::openElement('div', array('id' => 'central-auth-images', 'style' => 'position: absolute;')); foreach ($wgCentralAuthAutoLoginWikis as $wiki) { $wiki = WikiMap::getWiki($wiki); // Use WikiReference::getFullUrl(), returns a protocol-relative URL if needed $params = array('type' => '1x1', 'from' => wfWikiID()); $url = wfAppendQuery($wiki->getFullUrl('Special:CentralAutoLogin/start'), $params); if (self::isMobileDomain()) { $params['mobile'] = 1; // Do autologin on the mobile domain for each wiki $url = MobileContext::singleton()->getMobileUrl(wfAppendQuery($wiki->getFullUrl('Special:CentralAutoLogin/start'), $params)); } $html .= Xml::element('img', array('src' => $url, 'alt' => '', 'title' => '', 'width' => 1, 'height' => 1, 'style' => 'border: none;')); } if ($wgCentralAuthLoginWiki) { $wiki = WikiMap::getWiki($wgCentralAuthLoginWiki); // Use WikiReference::getFullUrl(), returns a protocol-relative URL if needed $url = wfAppendQuery($wiki->getFullUrl('Special:CentralAutoLogin/refreshCookies'), array('type' => '1x1', 'wikiid' => wfWikiID(), 'proto' => RequestContext::getMain()->getRequest()->detectProtocol())); $html .= Xml::element('img', array('src' => $url, 'alt' => '', 'title' => '', 'width' => 1, 'height' => 1, 'style' => 'border: none;')); } $html .= Xml::closeElement('div'); return $html; }
/** * Handler for MakeGlobalVariablesScript hook. * @see http://www.mediawiki.org/wiki/Manual:Hooks/MakeGlobalVariablesScript * @param &$vars array Variables to be added into the output * @param $outputPage OutputPage instance calling the hook * @return bool true in all cases */ public static function onMakeGlobalVariablesScript(array &$vars, OutputPage $out) { // If the device is a mobile, Remove the category entry. if (MobileContext::singleton()->shouldDisplayMobileView()) { unset($vars['wgCategories']); } return true; }
/** * Removes content inappropriate for mobile devices * @param bool $removeDefaults Whether default settings at $wgMFRemovableClasses should be used * @return array */ public function filterContent($removeDefaults = true) { $ctx = MobileContext::singleton(); $mfRemovableClasses = $ctx->getMFConfig()->get('MFRemovableClasses'); if ($removeDefaults) { $this->remove($mfRemovableClasses['base']); if ($ctx->isBetaGroupMember()) { $this->remove($mfRemovableClasses['beta']); } } if ($this->removeMedia) { $this->doRemoveImages(); } return parent::filterContent(); }