getSkin()->getTitle(); $this->isSpecialPage = $title->isSpecialPage(); $this->isSpecialMobileMenuPage = $this->isSpecialPage && $title->isSpecial( 'MobileMenu' ); $this->isMainPage = $title->isMainPage(); Hooks::run( 'MinervaPreRender', [ $this ] ); $this->render( $this->data ); } /** * Returns available page actions * @return array */ public function getPageActions() { return $this->isFallbackEditor() ? [] : $this->data['page_actions']; } /** * Returns template data for footer * * @param array $data Data used to build the page * @return array */ protected function getFooterTemplateData( $data ) { $groups = []; foreach ( $data['footerlinks'] as $category => $links ) { $items = []; foreach ( $links as $link ) { if ( isset( $this->data[$link] ) && $data[$link] !== '' && $data[$link] !== false ) { $items[] = [ 'category' => $category, 'name' => $link, 'linkhtml' => $data[$link], ]; } } $groups[] = [ 'name' => $category, 'items' => $items, ]; } // This turns off the footer id and allows us to distinguish the old footer with the new design return [ 'lastmodified' => $this->getHistoryLinkHtml( $data ), 'headinghtml' => $data['footer-site-heading-html'], // Note mobile-license is only available on the mobile skin. It is outputted as part of // footer-info on desktop hence the conditional check. 'licensehtml' => isset( $data['mobile-license'] ) ? $data['mobile-license'] : '', 'lists' => $groups, ]; } /** * Get the HTML for rendering the available page actions * @param array $data Data used to build page actions * @return string */ protected function getPageActionsHtml( $data ) { $actions = $this->getPageActions(); $html = ''; $isJSOnly = true; if ( $actions ) { foreach ( $actions as $key => $val ) { if ( isset( $val['is_js_only'] ) ) { if ( !$val['is_js_only'] ) { $isJSOnly = false; } unset( $val['is_js_only'] ); // no need to output this attribute } $html .= $this->makeListItem( $key, $val ); } $additionalClasses = $isJSOnly ? 'jsonly' : ''; $html = ''; } return $html; } /** * Returns the 'Last edited' message, e.g. 'Last edited on...' * @param array $data Data used to build the page * @return string */ protected function getHistoryLinkHtml( $data ) { $action = Action::getActionName( RequestContext::getMain() ); if ( isset( $data['historyLink'] ) && $action === 'view' ) { $args = [ 'clockIconClass' => MinervaUI::iconClass( 'clock-gray', 'before' ), 'arrowIconClass' => MinervaUI::iconClass( 'arrow-gray', 'element', 'mw-ui-icon-small mf-mw-ui-icon-rotate-anti-clockwise indicator', // Uses icon in MobileFrontend so must be prefixed mf. // Without MobileFrontend it will not render. // Rather than maintain 2 versions (and variants) of the arrow icon which can conflict // with each othe and bloat CSS, we'll // use the MobileFrontend one. Long term when T177432 and T160690 are resolved // we should be able to use one icon definition and break this dependency. 'mf' ), ] + $data['historyLink']; $templateParser = new TemplateParser( __DIR__ ); return $templateParser->processTemplate( 'history', $args ); } else { return ''; } } /** * @return bool */ protected function isFallbackEditor() { $action = $this->getSkin()->getRequest()->getVal( 'action' ); return $action === 'edit'; } /** * Get page secondary actions * @return string[] */ protected function getSecondaryActions() { if ( $this->isFallbackEditor() ) { return []; } return $this->data['secondary_actions']; } /** * Get HTML representing secondary page actions like language selector * @return string */ protected function getSecondaryActionsHtml() { $baseClass = MinervaUI::buttonClass( '', 'button' ); /** @var $skin SkinMinerva $skin */ $skin = $this->getSkin(); $html = ''; // no secondary actions on the user page if ( $skin instanceof SkinMinerva && !$skin->getUserPageHelper()->isUserPage() ) { foreach ( $this->getSecondaryActions() as $el ) { if ( isset( $el['attributes']['class'] ) ) { $el['attributes']['class'] .= ' ' . $baseClass; } else { $el['attributes']['class'] = $baseClass; } $html .= Html::element( 'a', $el['attributes'], $el['label'] ); } } return $html; } /** * Get the HTML for the content of a page * @param array $data Data used to build the page * @return string representing HTML of content */ protected function getContentHtml( $data ) { if ( !$data[ 'unstyledContent' ] ) { $content = Html::openElement( 'div', [ 'id' => 'bodyContent', 'class' => 'content', ] ); $content .= $data[ 'bodytext' ]; if ( isset( $data['subject-page'] ) ) { $content .= $data['subject-page']; } return $content . Html::closeElement( 'div' ); } else { return $data[ 'bodytext' ]; } } /** * Gets the main menu only on Special:MobileMenu. * On other pages the menu is rendered via JS. * @param array $data Data used to build the page * @return string */ protected function getMainMenuHtml( $data ) { if ( $this->isSpecialMobileMenuPage ) { $templateParser = new TemplateParser( __DIR__ . '/../../resources/skins.minerva.mainMenu/' ); return $templateParser->processTemplate( 'menu', $data['menu_data'] ); } else { return ''; } } /** * Render the entire page * @param array $data Data used to build the page * @todo replace with template engines */ protected function render( $data ) { $templateParser = new TemplateParser( __DIR__ ); $internalBanner = $data[ 'internalBanner' ]; $preBodyHtml = isset( $data['prebodyhtml'] ) ? $data['prebodyhtml'] : ''; $hasHeadingHolder = $internalBanner || $preBodyHtml || isset( $data['page_actions'] ); $hasPageActions = !$this->isSpecialPage && !$this->isMainPage; // prepare template data $templateData = [ 'banners' => $data['banners'], 'wgScript' => $data['wgScript'], 'isAnon' => $data['username'] === null, 'search' => $data['search'], 'placeholder' => wfMessage( 'mobile-frontend-placeholder' ), 'headelement' => $data[ 'headelement' ], 'menuButton' => $data['menuButton'], 'siteheading' => $data['footer-site-heading-html'], 'mainPageURL' => Title::newMainPage()->getLocalUrl(), // A button when clicked will submit the form // This is used so that on tablet devices with JS disabled the search button // passes the value of input to the search // We avoid using input[type=submit] as these cannot be easily styled as mediawiki ui icons // which is problematic in Opera Mini (see T140490) 'searchButton' => Html::rawElement( 'button', [ 'id' => 'searchIcon', 'class' => MinervaUI::iconClass( 'magnifying-glass', 'element', 'skin-minerva-search-trigger' ), ], wfMessage( 'searchbutton' ) ), 'secondaryButtonData' => $data['secondaryButtonData'], 'mainmenuhtml' => $this->getMainMenuHtml( $data ), 'hasheadingholder' => $hasHeadingHolder, 'taglinehtml' => $data['taglinehtml'], 'internalBanner' => $internalBanner, 'prebodyhtml' => $preBodyHtml, 'headinghtml' => isset( $data['headinghtml'] ) ? $data['headinghtml'] : '', 'postheadinghtml' => isset( $data['postheadinghtml'] ) ? $data['postheadinghtml'] : '', 'haspageactions' => $hasPageActions, 'pageactionshtml' => $hasPageActions ? $this->getPageActionsHtml( $data ) : '', 'subtitle' => $data['subtitle'], 'contenthtml' => $this->getContentHtml( $data ), 'secondaryactionshtml' => $this->getSecondaryActionsHtml(), 'footer' => $this->getFooterTemplateData( $data ), 'isBeta' => $this->getSkin()->getSkinOption( SkinMinerva::OPTIONS_MOBILE_BETA ), ]; // begin rendering echo $templateParser->processTemplate( 'minerva', $templateData ); $this->printTrail(); ?>