Foxtrott has submitted this change and it was merged. Change subject: Several improvements to the navbar ......................................................................
Several improvements to the navbar * split off navmenu into its own class * page tools: allow hiding link to current namespace * page tools: don't display if there are no tools (e.g. Special Pages) * improve navhead.xml (flatten nav menu, hide link to current namespace) * fix z-index of navbars Change-Id: Iba41064af7fe36946143841d55bde2860ac91cb4 --- M chameleon.php A includes/components/NavMenu.php M includes/components/NavbarHorizontal.php M includes/components/PageTools.php M layouts/navhead.xml M styles/screen.less 6 files changed, 286 insertions(+), 117 deletions(-) Approvals: Foxtrott: Verified; Looks good to me, approved diff --git a/chameleon.php b/chameleon.php index dbaab4f..56a2299 100644 --- a/chameleon.php +++ b/chameleon.php @@ -73,7 +73,7 @@ 'Cell', 'Grid', 'NavbarHorizontal', - 'NavHead', + 'NavMenu', 'PageTools', 'NewtalkNotifier', 'PersonalTools', diff --git a/includes/components/NavMenu.php b/includes/components/NavMenu.php new file mode 100644 index 0000000..2a10995 --- /dev/null +++ b/includes/components/NavMenu.php @@ -0,0 +1,154 @@ +<?php +/** + * File holding the NavMenu class + * + * @copyright (C) 2014, Stephan Gambke + * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License, version 3 (or later) + * + * This file is part of the MediaWiki extension Chameleon. + * The Chameleon extension is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Chameleon extension is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @file + * @ingroup Skins + */ + +namespace skins\chameleon\components; + +use Linker; +use skins\chameleon\IdRegistry; + +/** + * The NavMenu class. + * + * + * @ingroup Skins + */ +class NavMenu extends Component { + + /** + * Builds the HTML code for this component + * + * @return String the HTML code + */ + public function getHtml() { + + $ret = ''; + + $sidebar = $this->getSkinTemplate()->getSidebar( array( + 'search' => false, 'toolbox' => false, 'languages' => false + ) + ); + + $msg = \Message::newFromKey( 'skin-chameleon-navmenu-flatten' ); + + if ( $msg->exists() ) { + $flatten = array_map( trim, explode( ';', $msg->plain() ) ); + } elseif ( $this->getDomElement() !== null ) { + $flatten = array_map( trim, explode( ';', $this->getDomElement()->getAttribute( 'flatten' ) ) ); + } else { + $flatten = array(); + } + + // create a dropdown for each sidebar box + foreach ( $sidebar as $boxName => $box ) { + + $ret .= $this->getDropdownForNavMenu( $boxName, $box, array_search( $boxName, $flatten ) !== false ); + } + + return $ret; + } + + /** + * Create a single dropdown + * + * @param string $boxName + * @param array $box + * @param bool $flatten + * + * @return string + */ + protected function getDropdownForNavMenu( $boxName, $box, $flatten = false ) { + + // open list item containing the dropdown + $ret = $this->indent() . '<!-- ' . $boxName . ' -->'; + + $menuitems = ''; + + // build the list of submenu items + if ( is_array( $box[ 'content' ] ) && count( $box[ 'content' ] ) > 0 ) { + + $this->indent( $flatten ? 0 : 2 ); + + foreach ( $box[ 'content' ] as $key => $item ) { + $menuitems .= $this->indent() . $this->getSkinTemplate()->makeListItem( $key, $item ); + } + + $this->indent( $flatten ? 0 : -2 ); + + } else { + $menuitems .= $this->indent() . '<!-- empty -->'; + } + + if ( $flatten ) { + // if the menu is to be flattened, just return the introducing comment and the list of menu items as is + + $ret .= $menuitems; + + } elseif ( !is_array( $box[ 'content' ] ) || count( $box[ 'content' ] ) === 0 ) { + //if the menu is not to be flattened, but is empty, return an inert link + + $ret .= $this->indent() . \Html::rawElement( 'li', + array( + 'class' => '', + 'title' => Linker::titleAttrib( $box[ 'id' ] ) + ), + '<a href="#">' . htmlspecialchars( $box[ 'header' ] ) . '</a>' + ); + + } else { + + // open list item containing the dropdown + $ret .= $this->indent() . \Html::openElement( 'li', + array( + 'class' => 'dropdown', + 'title' => Linker::titleAttrib( $box[ 'id' ] ) + ) + ); + + // add the dropdown toggle + $ret .= $this->indent( 1 ) . '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . + htmlspecialchars( $box[ 'header' ] ) . ' <b class="caret"></b></a>'; + + // open list of dropdown menu items + $ret .= $this->indent() . + $this->indent() . \Html::openElement( 'ul', + array( + 'class' => 'dropdown-menu ' . $box[ 'id' ], + 'id' => IdRegistry::getRegistry()->getId( $box[ 'id' ] ), + ) + ); + + // add list of menu items + $ret .= $menuitems; + + // close list of dropdown menu items and the list item containing the dropdown + $ret .= + $this->indent() . '</ul>' . + $this->indent( -1 ) . '</li>'; + } + + return $ret; + } + +} diff --git a/includes/components/NavbarHorizontal.php b/includes/components/NavbarHorizontal.php index 2714f63..93b2b4b 100644 --- a/includes/components/NavbarHorizontal.php +++ b/includes/components/NavbarHorizontal.php @@ -26,7 +26,6 @@ namespace skins\chameleon\components; use Linker; -use Sanitizer; use skins\chameleon\IdRegistry; /** @@ -55,10 +54,13 @@ $this->indent() . \HTML::openElement( 'nav', array( 'class' => 'navbar navbar-default p-navbar ' . $this->getClassString(), - 'role' => 'navigation', - 'id' => IdRegistry::getRegistry()->getId('p-navbar') - )) . + 'role' => 'navigation', + 'id' => IdRegistry::getRegistry()->getId( 'p-navbar' ) + ) + ) . $this->indent( 1 ) . '<ul class="nav navbar-nav">'; + + $this->indent( 1 ); // add components $this->eachChild( function ( \DOMElement $node ) { @@ -69,19 +71,19 @@ switch ( $node->getAttribute( 'type' ) ) { case 'Logo': - $this->mHtml .= $this->getLogo(); + $this->mHtml .= $this->getLogo( $node ); break; case 'NavMenu': - $this->mHtml .= $this->getNavMenu(); + $this->mHtml .= $this->getNavMenu( $node ); break; case 'PageTools': - $this->mHtml .= $this->getPageTools(); + $this->mHtml .= $this->getPageTools( $node ); break; case 'SearchBar': - $this->mHtml .= $this->getSearchBar(); + $this->mHtml .= $this->getSearchBar( $node ); break; case 'PersonalTools': - $this->mHtml .= $this->getPersonalTools(); + $this->mHtml .= $this->getPersonalTools( $node ); break; } } @@ -96,11 +98,13 @@ /** * Creates HTML code for the wiki logo in a navbar * + * @param \DOMElement $domElement + * * @return String */ - protected function getLogo() { + protected function getLogo( \DOMElement $domElement = null ) { - $logo = new Logo( $this->getSkinTemplate(), null, $this->getIndent() ); + $logo = new Logo( $this->getSkinTemplate(), $domElement, $this->getIndent() ); $logo->addClasses( 'navbar-brand' ); return $logo->getHtml(); @@ -109,112 +113,56 @@ /** * Create a dropdown containing the page tools (page, talk, edit, history, ...) * + * @param \DOMElement $domElement + * * @return string */ - protected function getPageTools() { + protected function getPageTools( \DOMElement $domElement = null ) { - $pageTools = new PageTools( $this->getSkinTemplate(), null, $this->indent( 1 ) ); + $pageTools = new PageTools( $this->getSkinTemplate(), $domElement, $this->getIndent() ); $pageTools->setFlat( true ); $pageTools->removeClasses( 'text-center list-inline' ); $pageTools->addClasses( 'dropdown-menu' ); - $ret = $this->indent() . '<!-- page tools -->' . - $this->indent() . \Html::openElement( 'li', array( 'class' => 'dropdown' ) ); + $ret = $pageTools->getHtml(); - $ret .= '<a data-toggle="dropdown" class="dropdown-toggle" href="#">Page Tools <b class="caret"></b></a>' . $pageTools->getHtml() . '</li>'; - + if ( $ret !== '' ) { + $ret = + $this->indent() . '<!-- page tools -->' . + $this->indent() . \Html::openElement( 'li', array( 'class' => 'dropdown' ) ) . + $this->indent( 1 ) . '<a data-toggle="dropdown" class="dropdown-toggle" href="#">Page Tools <b class="caret"></b></a>' . + $ret . + $this->indent( -1 ) . '</li>' . "\n"; + } return $ret; } /** * Creates a list of navigational links usually found in the sidebar * - * @return string - */ - protected function getNavMenu() { - - $ret = ''; - - $this->indent( 1 ); - $sidebar = $this->getSkinTemplate()->getSidebar( array( - 'search' => false, 'toolbox' => false, 'languages' => false - ) - ); - - // create a dropdown for each sidebar box - foreach ( $sidebar as $boxName => $box ) { - - $ret .= $this->getDropdownForNavMenu( $boxName, $box ); - } - - return $ret; - } - - /** - * Create a single dropdown - * - * @param $boxName - * @param $box + * @param \DOMElement $domElement * * @return string */ - protected function getDropdownForNavMenu( $boxName, $box ) { + protected function getNavMenu( \DOMElement $domElement = null ) { - // open list item containing the dropdown - $ret = $this->indent() . '<!-- ' . $boxName . ' -->' . - $this->indent() . \Html::openElement( 'li', - array( - 'class' => 'dropdown', - 'title' => Linker::titleAttrib( $box[ 'id' ] ) - ) - ); + $navMenu = new NavMenu( $this->getSkinTemplate(), $domElement, $this->getIndent() ); - $this->indent( 1 ); - if ( is_array( $box[ 'content' ] ) && count( $box[ 'content' ] ) > 0 ) { + return $navMenu->getHtml() . "\n"; - // the dropdown toggle - $ret .= $this->indent() . '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . - htmlspecialchars( $box[ 'header' ] ) . ' <b class="caret"></b></a>'; - - // open list of dropdown menu items - $ret .= $this->indent() . - $this->indent() . \Html::openElement( 'ul', - array( - 'class' => 'dropdown-menu ' . Sanitizer::escapeId( $box[ 'id' ] ), - 'id' => IdRegistry::getRegistry()->getId( Sanitizer::escapeId( $box[ 'id' ] ) ), - ) - ); - - // output dropdown menu items - $this->indent( 1 ); - foreach ( $box[ 'content' ] as $key => $item ) { - $ret .= $this->indent() . $this->getSkinTemplate()->makeListItem( $key, $item ); - } - - // close list of dropdown menu items - $ret .= $this->indent( -1 ) . '</ul>'; - - } else { - $ret .= $this->indent() . '<a href="#">' . htmlspecialchars( $box[ 'header' ] ) . '</a>'; - } - $this->indent( -1 ); - - // close list item - $ret .= $this->indent() . '</li>'; - - return $ret; } /** * Creates a user's personal tools and the newtalk notifier * + * @param \DOMElement $domElement + * * @return string */ - protected function getPersonalTools() { + protected function getPersonalTools( \DOMElement $domElement = null ) { $user = $this->getSkinTemplate()->getSkin()->getUser(); - if ( $user->isLoggedIn() ) { $toolsClass = 'navbar-userloggedin'; @@ -226,7 +174,9 @@ // start personal tools element - $ret = $this->indent() . '<ul class="navbar-right navbar-nav navbar-personaltools" >' . + $ret = + $this->indent() . '<!-- personal tools -->' . + $this->indent() . '<ul class="navbar-right navbar-nav navbar-personaltools" >' . $this->indent( 1 ) . '<li class="dropdown navbar-personaltools-tools">' . $this->indent( 1 ) . '<a class="dropdown-toggle glyphicon glyphicon-user ' . $toolsClass . '" href="#" data-toggle="dropdown" title="' . $toolsLinkText . '" ></a>' . $this->indent() . '<ul class="p-personal-tools dropdown-menu" >'; @@ -274,9 +224,9 @@ return $ret; } - protected function getSearchBar() { + protected function getSearchBar( \DOMElement $domElement = null ) { - $search = new SearchBar( $this->getSkinTemplate(), null, $this->getIndent() ); + $search = new SearchBar( $this->getSkinTemplate(), $domElement, $this->getIndent() ); $search->addClasses( 'navbar-form' ); return $search->getHtml(); diff --git a/includes/components/PageTools.php b/includes/components/PageTools.php index 8272b96..cf7b6aa 100644 --- a/includes/components/PageTools.php +++ b/includes/components/PageTools.php @@ -25,7 +25,9 @@ namespace skins\chameleon\components; +use MWNamespace; use skins\chameleon\ChameleonTemplate; +use skins\chameleon\IdRegistry; /** * The PageTools class. @@ -40,7 +42,7 @@ private $mFlat = false; - public function __construct( ChameleonTemplate $template, $domElement, $indent = 0 ) { + public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) { parent::__construct( $template, $domElement, $indent ); @@ -56,12 +58,18 @@ */ public function getHtml() { - $ret = $this->indent() . '<!-- Content navigation -->' . - $this->indent() . '<ul class="p-contentnavigation ' . $this->getClassString() . '" id="p-contentnavigation">'; - $navigation = $this->getSkinTemplate()->data[ 'content_navigation' ]; - $this->indent( 1 ); + $hideSelectedNameSpace = filter_var( $this->getDomElement()->getAttribute( 'hideSelectedNameSpace' ), FILTER_VALIDATE_BOOLEAN ); + + if ( $hideSelectedNameSpace ) { + $namespacekey = $this->getNamespaceKey(); + unset( $navigation['namespaces'][ $namespacekey ] ); + } + + $ret = ''; + + $this->indent( 2 ); foreach ( $navigation as $category => $tabs ) { // TODO: visually group all links of one category (e.g. some space between categories) @@ -74,11 +82,13 @@ if ( !$this->mFlat ) { // output the name of the current category (e.g. 'namespaces', 'views', ...) - $ret .= $this->indent() . '<li id="p-' . $category . '" >' . - $this->indent( 1 ) . '<ul class="list-inline" >'; + $ret .= $this->indent() . + \Html::openElement( 'li', array( 'id' => IdRegistry::getRegistry()->getId( 'p-' . $category ) ) ) . + $this->indent( 1 ) . '<ul class="list-inline" >'; + + $this->indent( 1 ); } - $this->indent( 1 ); foreach ( $tabs as $key => $tab ) { // skip redundant links (i.e. the 'view' link) @@ -102,8 +112,19 @@ $this->indent( -1 ) . '</li>'; } } + $this->indent( -2 ); - $ret .= $this->indent( -1 ) . '</ul>' . "\n"; + if ( $ret !== '' ){ + $ret = $this->indent( 1 ) . '<!-- Content navigation -->' . + $this->indent() . + \Html::openElement( 'ul', + array( + 'class' => 'p-contentnavigation ' . $this->getClassString(), + 'id' => IdRegistry::getRegistry()->getId( 'p-contentnavigation' ), + ) ) . + $ret . + $this->indent() . '</ul>'; + } return $ret; } @@ -117,4 +138,43 @@ $this->mFlat = $flat; } + /** + * Generate strings used for xml 'id' names in tabs + * + * Stolen from MW's Title::getNamespaceKey() + * + * Difference: This function here reports the actual namespace while the one in Title reports the subject namespace, + * i.e. no talk namespaces + * + * @return mixed|string + */ + public function getNamespaceKey() { + global $wgContLang; + + // Gets the subject namespace if this title + $namespace = $this->getSkinTemplate()->getSkin()->getTitle()->getNamespace(); + + // Checks if canonical namespace name exists for namespace + if ( MWNamespace::exists( $this->getSkinTemplate()->getSkin()->getTitle()->getNamespace() ) ) { + // Uses canonical namespace name + $namespaceKey = MWNamespace::getCanonicalName( $namespace ); + } else { + // Uses text of namespace + $namespaceKey = $this->getSkinTemplate()->getSkin()->getTitle()->getNsText(); + } + + // Makes namespace key lowercase + $namespaceKey = $wgContLang->lc( $namespaceKey ); + // Uses main + if ( $namespaceKey == '' ) { + $namespaceKey = 'main'; + } + // Changes file to image for backwards compatibility + if ( $namespaceKey == 'file' ) { + $namespaceKey = 'image'; + } + return $namespaceKey; + } + + } diff --git a/layouts/navhead.xml b/layouts/navhead.xml index 7ea8a38..fbe694c 100644 --- a/layouts/navhead.xml +++ b/layouts/navhead.xml @@ -5,8 +5,8 @@ <cell span="12"> <component type="NavbarHorizontal"> <component type="Logo"></component> - <component type="NavMenu"></component> - <component type="PageTools"></component> + <component type="NavMenu" flatten="navigation"></component> + <component type="PageTools" hideSelectedNameSpace="1"></component> <component type="PersonalTools"></component> <component type="SearchBar"></component> </component> diff --git a/styles/screen.less b/styles/screen.less index d33cad1..1871e64 100644 --- a/styles/screen.less +++ b/styles/screen.less @@ -31,14 +31,18 @@ @navbar-newtalk-available: @brand-primary; @navbar-newtalk-available-hover: darken(@navbar-newtalk-available, 20%); -// if the navbar is in the first row (i.e. at the top of the page) add some margin +// if the navbar is in the first row (i.e. at the top of the page) add some margin at the top .container > *:first-child .navbar { margin-top: (@grid-gutter-width / 2); } +.navbar { -.navbar .nav { - width: 100%; + z-index: auto; + + .nav { + width: 100%; + } } // override some navbar-brand styles to accommodate an image and include a separator to the rest of the navbar @@ -55,7 +59,7 @@ } } -// styles for personal tools in the navhead component +// styles for personal tools in the navbar component .navbar-personaltools { .nav(); @@ -115,7 +119,7 @@ } - &:last-child > a, &.open:last-child > a { + &:last-child > a, &.open:last-child > a { border: none; } @@ -125,7 +129,7 @@ .mw-body { padding: 0 2em; - margin: 1em 0; + margin: 1em 0; } .catlinks { @@ -133,14 +137,14 @@ } .firstHeading { - border-bottom: 1px solid #eeeeee; + border-bottom: 1px solid #eeeeee; padding-bottom: .2em; - margin-bottom: .2em; + margin-bottom: .2em; } .contentHeader { - margin: 1em 0 1.5em; - border-bottom: 0; + margin: 1em 0 1.5em; + border-bottom: 0; padding-bottom: 0; } @@ -162,7 +166,7 @@ margin-bottom: 10px; } -.p-contentnavigation{ +.p-contentnavigation { a.selected { font-style: italic; @@ -205,11 +209,11 @@ &, &:hover, &:focus { - color: @nav-tabs-active-link-hover-color; - background-color: @nav-tabs-active-link-hover-bg; - border: 1px solid @nav-tabs-active-link-hover-border-color; + color: @nav-tabs-active-link-hover-color; + background-color: @nav-tabs-active-link-hover-bg; + border: 1px solid @nav-tabs-active-link-hover-border-color; border-bottom-color: transparent; - cursor: default; + cursor: default; } } } @@ -217,3 +221,4 @@ .navbar .p-contentnavigation li { display: block; } + -- To view, visit https://gerrit.wikimedia.org/r/122266 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iba41064af7fe36946143841d55bde2860ac91cb4 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/skins/chameleon Gerrit-Branch: master Gerrit-Owner: Foxtrott <s7ep...@gmail.com> Gerrit-Reviewer: Foxtrott <s7ep...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits