/**
  * Returns an array with details for a talk button.
  * @param Title $talkTitle Title object of the talk page
  * @param array $talkButton Array with data of desktop talk button
  * @return array
  */
 protected function getTalkButton($talkTitle, $talkButton)
 {
     $button = parent::getTalkButton($talkTitle, $talkButton);
     // use a button with icon in beta
     $button['attributes']['class'] = MobileUI::iconClass('talk', 'before', 'talk icon-32px');
     return $button;
 }
 /**
  * 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);
 }
 /**
  * Renders a banner telling the user the page is unavailable
  *
  * @param string $msg Message to display
  */
 protected function renderUnavailableBanner($msg)
 {
     $out = $this->getOutput();
     $out->setPageTitle($this->msg('mobile-frontend-requires-title'));
     $out->setProperty('unstyledContent', true);
     $out->addHTML(MobileUI::warningBox($msg));
 }
 /**
  * Get the link to users talk page
  * @return string
  */
 protected function getTalkLink()
 {
     // replace secondary icon
     $attrs = array('class' => MobileUI::iconClass('talk', 'before', MobileUI::buttonClass()), 'href' => $this->targetUser->getTalkPage()->getLocalUrl());
     // FIXME: What if this is the user's own profile? Should we change the message?
     return Html::element('a', $attrs, $this->msg('mobile-frontend-profile-usertalk', $this->targetUser->getName()));
 }
 /**
  * Render the special page
  * @param string|null $par Username to get uploads from
  */
 public function executeWhenAvailable($par = '')
 {
     if (($par === '' || $par === null) && $this->getUser()->isAnon()) {
         // Anons don't get to see Special:Uploads
         $this->requireLogin('mobile-frontend-donate-image-anon');
     } else {
         // uploads by a particular user, i.e Special:Uploads/username, are shown even to anons
         $this->setHeaders();
         $output = $this->getOutput();
         $output->addJsConfigVars('wgMFPhotoUploadEndpoint', $this->getMFConfig()->get('MFPhotoUploadEndpoint'));
         if ($par !== '' && $par !== null) {
             $user = User::newFromName($par);
             if (!$user || $user->isAnon()) {
                 $output->setPageTitle($this->msg('mobile-frontend-donate-image-title-username', $par));
                 $output->setStatusCode(404);
                 $html = MobileUI::contentElement(MobileUI::errorBox($this->msg('mobile-frontend-photo-upload-invalid-user', $par)));
             } else {
                 if ($user->equals($this->getUser())) {
                     $output->setPageTitle($this->msg('mobile-frontend-donate-image-title-you'));
                 } else {
                     $output->setPageTitle($this->msg('mobile-frontend-donate-image-title-username', $par));
                 }
                 $html = $this->getUserUploadsPageHtml($user);
             }
         } else {
             $user = $this->getUser();
             $output->setPageTitle($this->msg('mobile-frontend-donate-image-title-you'));
             // TODO: what if the user cannot upload to the destination wiki in $wgMFPhotoUploadEndpoint?
             $html = $this->getUserUploadsPageHtml($user);
         }
         $output->addHTML($html);
     }
 }
 /**
  * Show error page, that the user does not exist, or no user provided
  * @param string $msgKey Message key to use as error message body
  * @return string
  */
 protected function displayNoUserError($msgKey)
 {
     $out = $this->getOutput();
     // generate a user friendly error with a meaningful message
     $html = MobileUI::contentElement(MobileUI::errorBox(Html::element('h2', array(), $this->msg('mobile-frontend-profile-error')) . Html::element('p', array(), $this->msg($msgKey))));
     // return page with status code 404, instead of 200 and output the error page
     $out->setStatusCode(404);
     $out->addHtml($html);
 }
 /**
  * Adds HTML to render a header at the top of the feed
  * @param Title|string $title The page to link to or a string to show
  */
 protected function renderHeaderBar($title)
 {
     if ($title instanceof Title) {
         $headerTitle = $this->getHeaderBarLink($title);
     } else {
         // manually style it as a userlink
         $headerTitle = Html::element('span', array('class' => MobileUI::iconClass('user', 'before', 'mw-mf-user icon-16px')), $title);
     }
     $this->getOutput()->addHtml(Html::openElement('div', array('class' => 'content-header')) . Html::openElement('h2', array()) . $headerTitle . Html::closeElement('h2') . Html::closeElement('div'));
 }
 /**
  * Render Special Page Nearby
  * @param string $par Parameter submitted as subpage
  */
 public function executeWhenAvailable($par = '')
 {
     $this->setHeaders();
     $output = $this->getOutput();
     // set config
     $output->addJsConfigVars('wgMFNearbyRange', $this->getMFConfig()->get('MFNearbyRange'));
     $output->setPageTitle(wfMessage('mobile-frontend-nearby-title')->escaped());
     $html = Html::openElement('div', array('class' => 'content-unstyled', 'id' => 'mw-mf-nearby')) . MobileUI::contentElement(MobileUI::errorBox(Html::element('h2', array(), wfMessage('mobile-frontend-nearby-requirements')) . Html::element('p', array(), wfMessage('mobile-frontend-nearby-requirements-guidance'))), 'noscript') . Html::closeElement('div');
     // #mw-mf-nearby
     $output->addHTML($html);
 }
 /**
  * Build the login page
  * @todo Refactor this into parent template
  */
 public function execute()
 {
     $action = $this->data['action'];
     $token = $this->data['token'];
     $watchArticle = $this->getArticleTitleToWatch();
     $stickHTTPS = $this->doStickHTTPS() ? Html::input('wpStickHTTPS', 'true', 'hidden') : '';
     $username = strlen($this->data['name']) ? $this->data['name'] : null;
     // @TODO make sure this also includes returnto and returntoquery from the request
     $query = array('type' => 'signup');
     // Security: $action is already filtered by SpecialUserLogin
     $actionQuery = wfCgiToArray($action);
     if (isset($actionQuery['returnto'])) {
         $query['returnto'] = $actionQuery['returnto'];
     }
     if (isset($actionQuery['returntoquery'])) {
         $query['returntoquery'] = $actionQuery['returntoquery'];
         // Allow us to distinguish sign ups from the left nav to logins.
         // This allows us to show them an edit tutorial when they return to the page.
         if ($query['returntoquery'] === 'welcome=yes') {
             $query['returntoquery'] = 'campaign=leftNavSignup';
         }
     }
     // For Extension:Campaigns
     $campaign = $this->getSkin()->getRequest()->getText('campaign');
     if ($campaign) {
         $query['campaign'] = $campaign;
     }
     // Check for permission to create new account first
     $user = $this->getRequestContext()->getUser();
     if ($user->isAllowed('createaccount')) {
         $signupLink = Linker::link(SpecialPage::getTitleFor('Userlogin'), wfMessage('mobile-frontend-main-menu-account-create')->text(), array('class' => 'mw-mf-create-account mw-ui-block'), $query);
     } else {
         $signupLink = '';
     }
     // Check for permission to reset password first
     if ($this->data['canreset'] && $this->data['useemail'] && $this->data['resetlink'] === true) {
         $passwordReset = Html::element('a', array('class' => 'mw-userlogin-help mw-ui-block', 'href' => SpecialPage::getTitleFor('PasswordReset')->getLocalUrl()), wfMessage('passwordreset')->text());
     } else {
         $passwordReset = '';
     }
     $login = Html::openElement('div', array('id' => 'mw-mf-login', 'class' => 'content'));
     $form = Html::openElement('div', array()) . Html::openElement('form', array('name' => 'userlogin', 'class' => 'user-login', 'method' => 'post', 'action' => $action)) . Html::openElement('div', array('class' => 'inputs-box')) . Html::input('wpName', $username, 'text', array('class' => 'loginText', 'placeholder' => wfMessage('mobile-frontend-username-placeholder')->text(), 'id' => 'wpName1', 'tabindex' => '1', 'size' => '20', 'required')) . Html::input('wpPassword', null, 'password', array('class' => 'loginPassword', 'placeholder' => wfMessage('mobile-frontend-password-placeholder')->text(), 'id' => 'wpPassword1', 'tabindex' => '2', 'size' => '20')) . Html::closeElement('div') . Html::input('wpRemember', '1', 'hidden') . Html::input('wpLoginAttempt', wfMessage('mobile-frontend-login')->text(), 'submit', array('id' => 'wpLoginAttempt', 'class' => $baseClass = MobileUI::buttonClass('constructive'), 'tabindex' => '3')) . Html::input('wpLoginToken', $token, 'hidden') . Html::input('watch', $watchArticle, 'hidden') . $stickHTTPS . Html::closeElement('form') . $passwordReset . $signupLink . Html::closeElement('div');
     echo $login;
     $this->renderGuiderMessage();
     $this->renderMessageHtml();
     echo $form;
     echo Html::closeElement('div');
 }
 /**
  * Renders an item in the feed
  * @param MWTimestamp $ts The time the edit occurred
  * @param string $diffLink url to the diff for the edit
  * @param string $username The username of the user that made the edit (absent if anonymous)
  * @param string $comment The edit summary
  * @param Title|null $title The title of the page that was edited
  * @param bool $isAnon Is the edit anonymous?
  * @param int|null $bytes Net number of bytes changed or null if not applicable
  * @param bool $isMinor Is the edit minor?
  * @return string HTML code
  *
  * @todo FIXME: use an array as an argument?
  */
 protected function renderFeedItemHtml($ts, $diffLink = '', $username = '', $comment = '', $title = null, $isAnon = false, $bytes = 0, $isMinor = false)
 {
     $output = $this->getOutput();
     $user = $this->getUser();
     $lang = $this->getLanguage();
     if ($isAnon) {
         $usernameClass = MobileUI::iconClass('anonymous', 'before', 'icon-16px mw-mf-user mw-mf-anon');
     } else {
         $usernameClass = MobileUI::iconClass('user', 'before', 'icon-16px mw-mf-user');
     }
     $html = Html::openElement('li', array('class' => 'page-summary'));
     if ($diffLink) {
         $html .= Html::openElement('a', array('href' => $diffLink, 'class' => 'title'));
     } else {
         $html .= Html::openElement('div', array('class' => 'title'));
     }
     if ($title) {
         $html .= Html::element('h3', array(), $title->getPrefixedText());
     }
     if ($username && $this->showUsername) {
         $html .= Html::element('p', array('class' => $usernameClass), $username);
     }
     $html .= Html::element('p', array('class' => 'edit-summary component truncated-text multi-line two-line'), $comment);
     if ($isMinor) {
         $html .= ChangesList::flag('minor');
     }
     $html .= Html::openElement('div', array('class' => 'list-thumb')) . Html::element('p', array('class' => 'timestamp'), $lang->userTime($ts, $user));
     if ($bytes) {
         $formattedBytes = $lang->formatNum($bytes);
         if ($bytes > 0) {
             $formattedBytes = '+' . $formattedBytes;
             $bytesClass = 'mw-mf-bytesadded';
         } else {
             $bytesClass = 'mw-mf-bytesremoved';
         }
         $html .= Html::element('p', array('class' => $bytesClass, 'dir' => 'ltr'), $formattedBytes);
     }
     $html .= Html::closeElement('div');
     if ($diffLink) {
         $html .= Html::closeElement('a');
     } else {
         $html .= Html::closeElement('div');
     }
     $html .= Html::closeElement('li');
     $output->addHtml($html);
 }
 /**
  * Render Login/Create specific template
  * @todo refactor this into parent template
  */
 public function execute()
 {
     $action = $this->data['action'];
     $token = $this->data['token'];
     $watchArticle = $this->getArticleTitleToWatch();
     $stickHTTPS = $this->doStickHTTPS() ? Html::input('wpStickHTTPS', 'true', 'hidden') : '';
     $username = strlen($this->data['name']) ? $this->data['name'] : null;
     // handle captcha
     $captchaHtml = '';
     if (isset($this->data['header'])) {
         $captchaHtml .= $this->data['header'];
     }
     if (isset($this->data['extrafields'])) {
         $captchaHtml .= $this->data['extrafields'];
     }
     $captcha = $this->handleCaptcha($captchaHtml);
     $form = Html::openElement('form', array('name' => 'userlogin2', 'method' => 'post', 'class' => 'user-login', 'action' => $action, 'id' => 'userlogin2')) . Html::openElement('div', array('class' => 'inputs-box')) . Html::input('wpName', $username, 'text', array('class' => 'loginText', 'placeholder' => wfMessage('mobile-frontend-username-placeholder')->text(), 'id' => 'wpName1', 'tabindex' => '1', 'size' => '20', 'required')) . Html::input('wpPassword', null, 'password', array('class' => 'loginPassword', 'placeholder' => wfMessage('mobile-frontend-password-placeholder')->text(), 'id' => 'wpPassword2', 'tabindex' => '2', 'size' => '20')) . Html::input('wpRetype', null, 'password', array('class' => 'loginPassword', 'placeholder' => wfMessage('mobile-frontend-password-confirm-placeholder')->text(), 'id' => 'wpRetype', 'tabindex' => '3', 'size' => '20')) . Html::input('wpEmail', null, 'email', array('class' => 'loginText', 'placeholder' => wfMessage('mobile-frontend-account-create-email-placeholder')->text(), 'id' => 'wpEmail', 'tabindex' => '4', 'size' => '20')) . Html::closeElement('div') . $captcha . Html::input('wpCreateaccount', wfMessage('mobile-frontend-account-create-submit')->text(), 'submit', array('id' => 'wpCreateaccount', 'class' => MobileUI::buttonClass('constructive'), 'tabindex' => '6')) . Html::input('wpRemember', '1', 'hidden') . Html::input('wpCreateaccountToken', $token, 'hidden') . Html::input('watch', $watchArticle, 'hidden') . $stickHTTPS . Html::closeElement('form');
     echo Html::openElement('div', array('id' => 'mw-mf-accountcreate', 'class' => 'content'));
     $this->renderMessageHtml('signup', true);
     echo $form;
     echo Html::closeElement('div');
 }
 public function execute($par = '')
 {
     $this->setHeaders();
     $this->outputHeader();
     $out = $this->getOutput();
     $out->disallowUserJs();
     # Prevent hijacked user scripts from sniffing passwords etc.
     $this->requireLogin('prefsnologintext2');
     $this->checkReadOnly();
     if ($this->getRequest()->getCheck('success')) {
         $out->wrapWikiMsg("<div class=\"alert successbox\">\$1</div>", 'savedprefs');
     }
     if ($par && in_array($par, $this->validTabs)) {
         $htmlForm = $this->getPreferencesForm($par);
         $htmlForm->setSubmitCallback(array('Preferences', 'tryUISubmit'));
         $htmlForm->show();
     } else {
         foreach ($this->validTabs as $tabName) {
             $attrs = array('class' => $baseClass = MobileUI::buttonClass('block'), 'href' => SpecialPage::getTitleFor($this->getName(), $tabName)->getLocalUrl());
             $button = Html::element('a', $attrs, $this->msg("prefs-{$tabName}"));
             $out->addHtml($button);
         }
     }
 }
    /**
     * Render the settings form (with actual set settings) to display to user
     */
    private function getSettingsForm()
    {
        $out = $this->getOutput();
        $context = MobileContext::singleton();
        $user = $this->getUser();
        $out->setPageTitle($this->msg('mobile-frontend-main-menu-settings-heading'));
        if ($this->getRequest()->getCheck('success')) {
            $out->wrapWikiMsg("<div class=\"successbox\"><strong>\n\$1\n</strong></div><div id=\"mw-pref-clear\"></div>", 'savedprefs');
        }
        $betaEnabled = $context->isBetaGroupMember();
        $imagesChecked = $context->imagesDisabled() ? '' : 'checked';
        // images are off when disabled
        $imagesBeta = $betaEnabled ? 'checked' : '';
        $imagesDescriptionMsg = $this->msg('mobile-frontend-settings-images-explain')->parse();
        $disableMsg = $this->msg('mobile-frontend-images-status')->parse();
        $betaEnableMsg = $this->msg('mobile-frontend-settings-beta')->parse();
        $betaDescriptionMsg = $this->msg('mobile-frontend-opt-in-explain')->parse();
        $saveSettings = $this->msg('mobile-frontend-save-settings')->escaped();
        $action = $this->getPageTitle()->getLocalURL();
        $html = Html::openElement('form', array('class' => 'mw-mf-settings', 'method' => 'POST', 'action' => $action));
        $token = $user->isLoggedIn() ? Html::hidden('token', $user->getEditToken()) : '';
        $returnto = Html::hidden('returnto', $this->returnToTitle->getFullText());
        // array to save the data of options, which should be displayed here
        $options = array();
        // image settings
        $options['images'] = array('checked' => $imagesChecked, 'label' => $disableMsg, 'description' => $imagesDescriptionMsg, 'name' => 'enableImages', 'id' => 'enable-images-toggle');
        // beta settings
        if ($this->getMFConfig()->get('MFEnableBeta')) {
            $options['beta'] = array('checked' => $imagesBeta, 'label' => $betaEnableMsg, 'description' => $betaDescriptionMsg, 'name' => 'enableBeta', 'id' => 'enable-beta-toggle');
        }
        $templateParser = new TemplateParser(__DIR__ . '/../../resources/mobile.special.mobileoptions.scripts');
        // @codingStandardsIgnoreStart Long line
        foreach ($options as $key => $data) {
            if (isset($data['type']) && $data['type'] === 'hidden') {
                $html .= Html::element('input', array('type' => 'hidden', 'name' => $data['name'], 'value' => $data['checked']));
            } else {
                $html .= $templateParser->processTemplate('checkbox', $data);
            }
        }
        $className = MobileUI::buttonClass('constructive');
        $html .= <<<HTML
\t\t<input type="submit" class="{$className}" id="mw-mf-settings-save" value="{$saveSettings}">
\t\t{$token}
\t\t{$returnto}
\t</form>
HTML;
        // @codingStandardsIgnoreEnd
        $out->addHTML($html);
    }
 /**
  * Render the contributions of user to page
  * @param ResultWrapper $res
  */
 protected function showContributions(ResultWrapper $res)
 {
     $numRows = $res->numRows();
     $rev = null;
     $out = $this->getOutput();
     $revs = array();
     $prevRevs = array();
     foreach ($res as $row) {
         $rev = new Revision($row);
         $revs[] = $rev;
         if ($res->key() <= self::LIMIT + 1 && $rev->getParentId()) {
             $prevRevs[] = $rev->getParentId();
         }
     }
     $this->prevLengths = Revision::getParentLengths(wfGetDB(DB_SLAVE), $prevRevs);
     if ($numRows > 0) {
         $count = 0;
         foreach ($revs as $rev) {
             if ($count++ < self::LIMIT) {
                 $this->showContributionsRow($rev);
             }
         }
         $out->addHtml('</ul>');
         // Captured 1 more than we should have done so if the number of
         // results is greater than the limit there are more to show.
         if ($numRows > self::LIMIT) {
             $out->addHtml($this->getMoreButton($rev->getTimestamp()));
         }
     } else {
         // For users who exist but have not made any edits
         $out->addHtml(MobileUI::warningBox($this->msg('mobile-frontend-history-no-results')));
     }
 }
 /**
  * Render the history list
  * @see showRow()
  * @see doQuery()
  * @param ResultWrapper $res The result of doQuery
  */
 protected function showHistory(ResultWrapper $res)
 {
     $numRows = $res->numRows();
     $rev1 = $rev2 = null;
     $out = $this->getOutput();
     if ($numRows > 0) {
         foreach ($res as $row) {
             $rev1 = new Revision($row);
             if ($rev2) {
                 $this->showRow($rev2, $rev1);
             }
             $rev2 = $rev1;
         }
         if ($rev1 && $numRows < self::LIMIT + 1) {
             $this->showRow($rev1, null);
         }
         $out->addHtml('</ul>');
         // Captured 1 more than we should have done so if the number of
         // results is greater than the limit there are more to show.
         if ($numRows > self::LIMIT) {
             $out->addHtml($this->getMoreButton($rev1->getTimestamp()));
         }
     } else {
         // Edge case.
         // I suspect this is here because revisions may exist but may have been hidden.
         $out->addHtml(MobileUI::warningBox($this->msg('mobile-frontend-history-no-results')));
     }
 }
 /**
  * Get the header for the watchlist page
  * @param User user
  * @return string Parsed HTML
  */
 public static function getWatchlistHeader(User $user)
 {
     $sp = SpecialPage::getTitleFor('Watchlist');
     $attrsList = $attrsFeed = array();
     $view = $user->getOption(SpecialMobileWatchlist::VIEW_OPTION_NAME, 'a-z');
     $filter = $user->getOption(SpecialMobileWatchlist::FILTER_OPTION_NAME, 'all');
     if ($view === 'feed') {
         $attrsList['class'] = MobileUI::buttonClass();
         // FIXME [MediaWiki UI] This probably be described as a different type of mediawiki ui element
         $attrsFeed['class'] = MobileUI::buttonClass('progressive', 'active');
     } else {
         $attrsFeed['class'] = MobileUI::buttonClass();
         // FIXME [MediaWiki UI] This probably be described as a different type of mediawiki ui element
         $attrsList['class'] = MobileUI::buttonClass('progressive', 'active');
     }
     $html = Html::openElement('ul', array('class' => 'button-bar mw-ui-button-group')) . Html::openElement('li', $attrsList) . Linker::link($sp, wfMessage('mobile-frontend-watchlist-a-z')->text(), array('class' => 'button'), array('watchlistview' => 'a-z')) . Html::closeElement('li') . Html::openElement('li', $attrsFeed) . Linker::link($sp, wfMessage('mobile-frontend-watchlist-feed')->text(), array('class' => 'button'), array('watchlistview' => 'feed', 'filter' => $filter)) . Html::closeElement('li') . Html::closeElement('ul');
     return '<div class="content-header">' . $html . '</div>';
 }
 /**
  * Returns an array of links for page secondary actions
  * @param BaseTemplate $tpl
  * @return Array
  */
 protected function getSecondaryActions(BaseTemplate $tpl)
 {
     $buttons = parent::getSecondaryActions($tpl);
     $title = $this->getTitle();
     $namespaces = $tpl->data['content_navigation']['namespaces'];
     if ($this->isTalkAllowed()) {
         // FIXME [core]: This seems unnecessary..
         $subjectId = $title->getNamespaceKey('');
         $talkId = $subjectId === 'main' ? 'talk' : "{$subjectId}_talk";
         $talkButton = isset($namespaces[$talkId]) && !$title->isTalkPage() ? $namespaces[$talkId]['text'] : '';
         $talkTitle = $title->getTalkPage();
         $buttons['talk'] = array('attributes' => array('href' => $talkTitle->getLinkURL(), 'class' => MobileUI::iconClass('talk', 'before', 'talk'), 'data-title' => $talkTitle->getFullText()), 'label' => $talkButton);
     }
     return $buttons;
 }
 /**
  * Gets HTML to place in the header bar
  * @param Title $title The page to link to
  * @return string HTML representing the link in the header bar
  */
 protected function getHeaderBarLink($title)
 {
     return Html::element('a', array('class' => MobileUI::iconClass('user', 'before', 'mw-mf-user icon-16px'), 'href' => SpecialPage::getTitleFor('UserProfile', $title->getText())->getLocalUrl()), $title->getText());
 }
 /**
  * Render the page with a list of languages the page is available in
  * @param string $pagename The name of the page
  */
 public function executeWhenAvailable($pagename)
 {
     if (!is_string($pagename) || $pagename === '') {
         wfHttpError(404, $this->msg('mobile-frontend-languages-404-title')->text(), $this->msg('mobile-frontend-languages-404-desc')->text());
         return;
     }
     $this->title = Title::newFromText($pagename);
     $output = $this->getOutput();
     $html = '';
     if ($this->title && $this->title->exists()) {
         $titlename = $this->title->getPrefixedText();
         $pageTitle = $this->msg('mobile-frontend-languages-header-page', $titlename)->text();
         $languages = $this->getLanguages();
         $variants = $this->getLanguageVariants();
         $languagesCount = count($languages);
         $variantsCount = count($variants);
         $html .= Html::element('p', array(), $this->msg('mobile-frontend-languages-text')->params($titlename)->numParams($languagesCount)->text());
         $html .= Html::openElement('p');
         $html .= Html::element('a', array('href' => $this->title->getLocalUrl()), $this->msg('returnto', $titlename)->text());
         $html .= Html::closeElement('p');
         if ($languagesCount > 0 || $variantsCount > 1) {
             // Language variants first
             if ($variantsCount > 1) {
                 $variantHeader = $variantsCount > 1 ? $this->msg('mobile-frontend-languages-variant-header')->text() : '';
                 $html .= Html::element('h2', array('id' => 'mw-mf-language-variant-header'), $variantHeader);
                 $html .= Html::openElement('ul', array('id' => 'mw-mf-language-variant-selection'));
                 foreach ($variants as $val) {
                     $html .= $this->makeLangListItem($val);
                 }
                 $html .= Html::closeElement('ul');
             }
             // Then other languages
             if ($languagesCount > 0) {
                 $languageHeader = $this->msg('mobile-frontend-languages-header')->text();
                 $html .= Html::element('h2', array('id' => 'mw-mf-language-header'), $languageHeader) . Html::openElement('ul', array('id' => 'mw-mf-language-selection'));
                 foreach ($languages as $val) {
                     $html .= $this->makeLangListItem($val);
                 }
                 $html .= Html::closeElement('ul');
             }
         }
     } else {
         $pageTitle = $this->msg('mobile-frontend-languages-header')->text();
         $html .= Html::element('p', array(), $this->msg('mobile-frontend-languages-nonexistent-title')->params($pagename)->text());
     }
     $html = MobileUI::contentElement($html);
     $output->setPageTitle($pageTitle);
     $output->addHTML($html);
 }
 /**
  * @inheritdoc
  */
 protected function getSearchForm($data)
 {
     return Html::openElement('form', array('action' => $data['wgScript'], 'class' => 'search-box')) . Html::openElement('div', array('class' => MobileUI::iconClass('search-invert', 'element', 'fulltext-search no-js-only'))) . $this->makeSearchButton('fulltext') . Html::closeElement('div') . Html::openElement('span') . $this->makeSearchInput($this->getSearchAttributes()) . Html::closeElement('span') . Html::closeElement('form');
 }
 /**
  * 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'));
 }
 /**
  * Prepare configured and available page actions
  * @param BaseTemplate $tpl
  */
 protected function preparePageActions(BaseTemplate $tpl)
 {
     $title = $this->getTitle();
     $noJsEdit = MobileContext::singleton()->getMFConfig()->get('MFAllowNonJavaScriptEditing');
     // Reuse template data variable from SkinTemplate to construct page menu
     $menu = array();
     $actions = $tpl->data['content_navigation']['actions'];
     if ($this->isUserPage) {
         if (!$this->getTitle()->exists()) {
             $tpl->set('page_actions', $menu);
             return;
         }
     }
     // empty placeholder for edit and photos which both require js
     if ($this->isAllowedPageAction('edit')) {
         $additionalClass = $noJsEdit ? ' nojs-edit' : '';
         $menu['edit'] = array('id' => 'ca-edit', 'text' => '', 'itemtitle' => $this->msg('mobile-frontend-pageaction-edit-tooltip'), 'class' => MobileUI::iconClass('edit-enabled', 'element' . $additionalClass), 'links' => array('edit' => array('href' => $this->getTitle()->getLocalUrl(array('action' => 'edit', 'section' => 0)))));
     }
     if ($this->isAllowedPageAction('watch')) {
         $watchTemplate = array('id' => 'ca-watch', 'class' => MobileUI::iconClass('watch', 'element', 'icon-32px watch-this-article hidden'));
         // standardise watch article into one menu item
         if (isset($actions['watch'])) {
             $menu['watch'] = array_merge($actions['watch'], $watchTemplate);
         } elseif (isset($actions['unwatch'])) {
             $menu['watch'] = array_merge($actions['unwatch'], $watchTemplate);
             $menu['watch']['class'] .= ' watched';
         } else {
             // placeholder for not logged in
             $menu['watch'] = $watchTemplate;
             // FIXME: makeLink (used by makeListItem) when no text is present defaults to use the key
             $menu['watch']['text'] = '';
             $menu['watch']['href'] = $this->getLoginUrl(array('returnto' => $title));
         }
     }
     $tpl->set('page_actions', $menu);
 }
 /**
  * Prepare configured and available page actions
  * @param BaseTemplate $tpl
  */
 protected function preparePageActions(BaseTemplate $tpl)
 {
     $title = $this->getTitle();
     // Reuse template data variable from SkinTemplate to construct page menu
     $menu = array();
     $actions = $tpl->data['content_navigation']['actions'];
     // empty placeholder for edit and photos which both require js
     if ($this->isAllowedPageAction('edit')) {
         $menu['edit'] = array('id' => 'ca-edit', 'text' => '', 'itemtitle' => $this->msg('mobile-frontend-pageaction-edit-tooltip'), 'class' => MobileUI::iconClass('edit', 'element', 'hidden'));
     }
     if ($this->isAllowedPageAction('watch')) {
         $watchTemplate = array('id' => 'ca-watch', 'class' => MobileUI::iconClass('watch', 'element', 'icon-32px watch-this-article hidden'));
         // standardise watch article into one menu item
         if (isset($actions['watch'])) {
             $menu['watch'] = array_merge($actions['watch'], $watchTemplate);
         } elseif (isset($actions['unwatch'])) {
             $menu['watch'] = array_merge($actions['unwatch'], $watchTemplate);
             $menu['watch']['class'] .= ' watched';
         } else {
             // placeholder for not logged in
             $menu['watch'] = $watchTemplate;
             // FIXME: makeLink (used by makeListItem) when no text is present defaults to use the key
             $menu['watch']['text'] = '';
             $menu['watch']['href'] = $this->getLoginUrl(array('returnto' => $title));
         }
     }
     $tpl->set('page_actions', $menu);
 }
 /**
  * Get HTML representing secondary page actions like language selector
  * @return string
  */
 protected function getSecondaryActionsHtml()
 {
     $baseClass = MobileUI::buttonClass('', 'button');
     $html = Html::openElement('div', array('id' => 'page-secondary-actions'));
     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 . Html::closeElement('div');
 }
 protected function getSearchAttributes()
 {
     $searchAttributes = parent::getSearchAttributes();
     $searchAttributes['class'] = MobileUI::semanticClass('mw-ui-input', '', 'search');
     return $searchAttributes;
 }
 /**
  * Render the footer including userinfos (Name, Role, Editcount)
  */
 function showFooter()
 {
     $output = $this->getOutput();
     $output->addHtml(Html::openElement('div', array('id' => 'mw-mf-userinfo', 'class' => 'position-fixed')) . Html::openElement('div', array('class' => 'post-content')));
     $userId = $this->rev->getUser();
     if ($userId) {
         $user = User::newFromId($userId);
         $edits = $user->getEditCount();
         $attrs = array('class' => MobileUI::iconClass('user', 'before', 'mw-mf-user icon-16px'), 'data-revision-id' => $this->revId, 'data-user-name' => $user->getName(), 'data-user-gender' => $user->getOption('gender'));
         $output->addHtml(Html::openElement('div', $attrs) . Linker::link($user->getUserPage(), htmlspecialchars($user->getName()), array('class' => 'mw-mf-user-link')) . '</div>' . '<div class="mw-mf-roles meta">' . $this->listGroups($user) . '</div>' . '<div class="mw-mf-edit-count meta">' . $this->msg('mobile-frontend-diffview-editcount', $this->getLanguage()->formatNum($edits))->parse() . '</div>');
     } else {
         $ipAddr = $this->rev->getUserText();
         $userPage = SpecialPage::getTitleFor('Contributions', $ipAddr);
         $output->addHtml(Html::element('div', array('class' => MobileUI::iconClass('anonymous', 'before', 'mw-mf-user icon-16px mw-mf-anon')), $this->msg('mobile-frontend-diffview-anonymous')) . '<div>' . Linker::link($userPage, htmlspecialchars($ipAddr)) . '</div>');
     }
     if ($this->mDiffEngine instanceof InlineDifferenceEngine) {
         $output->addHtml($this->mDiffEngine->getPatrolledLink());
     }
     $output->addHtml(Html::closeElement('div') . Html::closeElement('div'));
 }