summaryrefslogtreecommitdiff
path: root/www/wiki/skins/chameleon/src/Components
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
committerYaco <franco@reevo.org>2020-06-04 11:01:00 -0300
commitfc7369835258467bf97eb64f184b93691f9a9fd5 (patch)
treedaabd60089d2dd76d9f5fb416b005fbe159c799d /www/wiki/skins/chameleon/src/Components
first commit
Diffstat (limited to 'www/wiki/skins/chameleon/src/Components')
-rw-r--r--www/wiki/skins/chameleon/src/Components/Cell.php57
-rw-r--r--www/wiki/skins/chameleon/src/Components/Component.php222
-rw-r--r--www/wiki/skins/chameleon/src/Components/Container.php60
-rw-r--r--www/wiki/skins/chameleon/src/Components/ContentBody.php218
-rw-r--r--www/wiki/skins/chameleon/src/Components/ContentHeader.php76
-rw-r--r--www/wiki/skins/chameleon/src/Components/FooterIcons.php73
-rw-r--r--www/wiki/skins/chameleon/src/Components/FooterInfo.php83
-rw-r--r--www/wiki/skins/chameleon/src/Components/FooterPlaces.php64
-rw-r--r--www/wiki/skins/chameleon/src/Components/Grid.php59
-rw-r--r--www/wiki/skins/chameleon/src/Components/Html.php61
-rw-r--r--www/wiki/skins/chameleon/src/Components/LastmodInfo.php85
-rw-r--r--www/wiki/skins/chameleon/src/Components/LegalInfo.php85
-rw-r--r--www/wiki/skins/chameleon/src/Components/Logo.php98
-rw-r--r--www/wiki/skins/chameleon/src/Components/MainContent.php215
-rw-r--r--www/wiki/skins/chameleon/src/Components/Menu.php96
-rw-r--r--www/wiki/skins/chameleon/src/Components/Modifications/HideFor.php71
-rw-r--r--www/wiki/skins/chameleon/src/Components/Modifications/Modification.php174
-rw-r--r--www/wiki/skins/chameleon/src/Components/Modifications/ShowOnlyFor.php71
-rw-r--r--www/wiki/skins/chameleon/src/Components/Modifications/Sticky.php51
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavMenu.php221
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal.php256
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Logo.php54
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Menu.php51
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/NavMenu.php51
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageTools.php159
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageToolsAdaptable.php209
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PersonalTools.php117
-rw-r--r--www/wiki/skins/chameleon/src/Components/NavbarHorizontal/SearchBar.php55
-rw-r--r--www/wiki/skins/chameleon/src/Components/NewtalkNotifier.php57
-rw-r--r--www/wiki/skins/chameleon/src/Components/PageTools.php267
-rw-r--r--www/wiki/skins/chameleon/src/Components/PersonalTools.php82
-rw-r--r--www/wiki/skins/chameleon/src/Components/Row.php45
-rw-r--r--www/wiki/skins/chameleon/src/Components/SearchBar.php144
-rw-r--r--www/wiki/skins/chameleon/src/Components/Silent.php51
-rw-r--r--www/wiki/skins/chameleon/src/Components/SiteNotice.php59
-rw-r--r--www/wiki/skins/chameleon/src/Components/Structure.php96
-rw-r--r--www/wiki/skins/chameleon/src/Components/ToolbarHorizontal.php142
37 files changed, 4035 insertions, 0 deletions
diff --git a/www/wiki/skins/chameleon/src/Components/Cell.php b/www/wiki/skins/chameleon/src/Components/Cell.php
new file mode 100644
index 00000000..f46c8813
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Cell.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * File holding the Cell class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Skins\Chameleon\ChameleonTemplate;
+
+/**
+ * The Cell class.
+ *
+ * @ingroup Skins
+ */
+class Cell extends Container {
+
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+
+ if ( !is_null( $domElement ) ) {
+
+ $span = $domElement->getAttribute( 'span' );
+
+ if ( ( !is_int( $span ) && !ctype_digit( $span ) ) || ( $span < 1 ) || ( $span > 12 ) ) {
+ $span = '12';
+ }
+
+ } else {
+ $span = '12';
+ }
+
+ parent::__construct( $template, $domElement, $indent );
+
+ $this->addClasses( "col-lg-$span" );
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Component.php b/www/wiki/skins/chameleon/src/Components/Component.php
new file mode 100644
index 00000000..e6dc51c1
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Component.php
@@ -0,0 +1,222 @@
+<?php
+/**
+ * File containing the Component class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 SkinChameleon;
+use Skins\Chameleon\ChameleonTemplate;
+
+/**
+ * Component class
+ *
+ * This is the base class of all components.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+abstract class Component {
+
+ private $mSkinTemplate;
+ private $mIndent = 0;
+ private $mClasses = array();
+ private $mDomElement = null;
+
+ /**
+ * @param ChameleonTemplate $template
+ * @param \DOMElement|null $domElement
+ * @param int $indent
+ */
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+
+ $this->mSkinTemplate = $template;
+ $this->mIndent = (int) $indent;
+ $this->mDomElement = $domElement;
+
+ if ( $domElement !== null ) {
+ $this->addClasses( $domElement->getAttribute( 'class' ) );
+ }
+ }
+
+ /**
+ * Sets the class string that should be assigned to the top-level html element of this component
+ *
+ * @param string | array | null $classes
+ *
+ */
+ public function setClasses( $classes ) {
+
+ $this->mClasses = array();
+ $this->addClasses( $classes );
+
+ }
+
+ /**
+ * Adds the given class to the class string that should be assigned to the top-level html element of this component
+ *
+ * @param string | array | null $classes
+ *
+ * @return string | array
+ */
+ public function addClasses( $classes ) {
+
+ $classesArray = $this->transformClassesToArray( $classes );
+
+ if ( !empty( $classesArray ) ) {
+ $classesArray = array_combine( $classesArray, $classesArray );
+ $this->mClasses = array_merge( $this->mClasses, $classesArray );
+ }
+ }
+
+ /**
+ * @param string | array | null $classes
+ *
+ * @return array
+ * @throws \MWException
+ */
+ protected function transformClassesToArray ( $classes ) {
+
+ if ( empty( $classes ) ) {
+ return array();
+ } elseif ( is_array( $classes )) {
+ return $classes;
+ } elseif ( is_string( $classes ) ) {
+ return explode( ' ', $classes );
+ } else {
+ throw new \MWException( __METHOD__ . ': Expected String or Array; ' . getType( $classes ) . ' given.' );
+ }
+
+ }
+
+ /**
+ * @return ChameleonTemplate
+ */
+ public function getSkinTemplate() {
+
+ return $this->mSkinTemplate;
+ }
+
+ /**
+ * @since 1.1
+ * @return SkinChameleon
+ */
+ public function getSkin() {
+
+ return $this->mSkinTemplate->getSkin();
+ }
+
+ /**
+ * Returns the current indentation level
+ *
+ * @return int
+ */
+ public function getIndent() {
+
+ return $this->mIndent;
+ }
+
+ /**
+ * Returns the class string that should be assigned to the top-level html element of this component
+ *
+ * @return string
+ */
+ public function getClassString() {
+
+ return implode( ' ', $this->mClasses );
+ }
+
+ /**
+ * Removes the given class from the class string that should be assigned to the top-level html element of this component
+ *
+ * @param string | array | null $classes
+ *
+ * @return string
+ */
+ public function removeClasses( $classes ) {
+
+ $classesArray = $this->transformClassesToArray( $classes );
+
+ $this->mClasses = array_diff( $this->mClasses, $classesArray );
+ }
+
+ /**
+ * Returns the DOMElement from the description XML file associated with this element.
+ *
+ * @return \DOMElement
+ */
+ public function getDomElement() {
+ return $this->mDomElement;
+ }
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ abstract public function getHtml();
+
+ /**
+ * @return string[] the resource loader modules needed by this component
+ */
+ public function getResourceLoaderModules() {
+ return array();
+ }
+
+ /**
+ * Adds $indent to (or subtracts from if negative) the current indentation level.
+ * Inserts a new line and a number of tabs according to the new indentation level.
+ *
+ * @param int $indent
+ * @return string
+ * @throws \MWException
+ */
+ protected function indent( $indent = 0 ) {
+
+ $this->mIndent += (int) $indent;
+
+ if ( $this->mIndent < 0 ) {
+ throw new \MWException('Attempted HTML indentation of ' .$this->mIndent );
+ }
+
+ return "\n" . str_repeat( "\t", $this->mIndent );
+ }
+
+ /**
+ * @param string $attributeName
+ * @param null | string $default
+ * @return null | string
+ */
+ protected function getAttribute( $attributeName, $default = null ) {
+
+ $element = $this->getDomElement();
+
+ if ( $element !== null && $element->hasAttribute( $attributeName ) ) {
+ return $element->getAttribute( $attributeName );
+ }
+
+ return $default;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Container.php b/www/wiki/skins/chameleon/src/Components/Container.php
new file mode 100644
index 00000000..4aaa1675
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Container.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * File holding the Container class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+/**
+ * The Container class.
+ *
+ * It will wrap its content elements in a DIV.
+ *
+ * Supported attributes:
+ * - class
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Container extends Structure {
+
+ /**
+ * Builds the HTML code for the main container
+ *
+ * @return String the HTML code
+ */
+ public function getHtml(){
+
+ $ret = $this->indent() . \Html::openElement( 'div', array( 'class' => $this->getClassString() ) );
+ $this->indent( 1 );
+
+ $ret .= parent::getHtml();
+
+ $ret .= $this->indent( -1 ) . '</div>';
+
+ return $ret;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/ContentBody.php b/www/wiki/skins/chameleon/src/Components/ContentBody.php
new file mode 100644
index 00000000..336b8172
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/ContentBody.php
@@ -0,0 +1,218 @@
+<?php
+/**
+ * File holding the MainContent class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2016, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Skins\Chameleon\IdRegistry;
+
+/**
+ * The MainContent class.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class ContentBody extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $skintemplate = $this->getSkinTemplate();
+ $idRegistry = IdRegistry::getRegistry();
+
+ // START content
+ $ret =
+ $this->indent() . '<!-- start the content area -->' .
+ $this->indent() . $idRegistry->openElement( 'div',
+ array( 'id' => 'content', 'class' => 'mw-body ' . $this->getClassString() )
+ ) .
+
+ $idRegistry->element( 'a', array( 'id' => 'top' ) ) .
+ $this->indent(1) . $idRegistry->element( 'div', array( 'id' => 'mw-indicators', 'class' => 'mw-indicators', ), $this->buildMwIndicators() ) .
+
+ $this->indent() . '<div ' . \Html::expandAttributes( array(
+ 'id' => $idRegistry->getId( 'mw-js-message' ),
+ 'style' => 'display:none;'
+ )
+ ) . $skintemplate->get( 'userlangattributes' ) . '></div>';
+
+ // $ret .= $this->buildContentHeader();
+
+ if ( $skintemplate->get( 'subtitle' ) ) {
+
+ // TODO: should not use class 'small', better use class 'contentSub' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- subtitle line; used for various things like the subpage hierarchy -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub', 'class' => 'small' ), $skintemplate->get( 'subtitle' ) );
+ $ret .= '</br>';
+
+ }
+
+ if ( $skintemplate->get( 'undelete' ) ) {
+ // TODO: should not use class 'small', better use class 'contentSub2' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- undelete message -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub2', 'class' => 'small' ), $skintemplate->get( 'undelete' ) );
+ $ret .= '</br>';
+
+ }
+
+
+ $ret .= $this->buildContentBody();
+ $ret .= $this->buildCategoryLinks();
+
+ $ret .= $this->indent( -1 ) . '</div>';
+ // END content
+
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildContentHeader() {
+
+ $skintemplate = $this->getSkinTemplate();
+ $idRegistry = IdRegistry::getRegistry();
+
+ $ret = $this->indent() . '<div class ="contentHeader">' .
+
+ $this->indent( 1 ) . '<!-- title of the page -->' .
+ $this->indent() . $idRegistry->element( 'h1', array( 'id' => 'firstHeading', 'class' => 'firstHeading' ), $skintemplate->get( 'title' ) ) .
+
+ $this->indent() . '<!-- tagline; usually goes something like "From WikiName" primary purpose of this seems to be for printing to identify the source of the content -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id'=> 'siteSub' ), $skintemplate->getMsg( 'tagline' )->escaped() );
+
+ if ( $skintemplate->get( 'subtitle' ) ) {
+
+ // TODO: should not use class 'small', better use class 'contentSub' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- subtitle line; used for various things like the subpage hierarchy -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub', 'class' => 'small' ), $skintemplate->get( 'subtitle' ) );
+
+ }
+
+ if ( $skintemplate->get( 'undelete' ) ) {
+ // TODO: should not use class 'small', better use class 'contentSub2' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- undelete message -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub2', 'class' => 'small' ), $skintemplate->get( 'undelete' ) );
+ }
+
+ // TODO: Do we need this? Seems to be an accessibility thing. It's used
+ // in vector to jump to the nav which is at the bottom of the document,
+ // but our nav is usually at the top
+ $ret .= $idRegistry->element( 'div', array( 'id' => 'jump-to-nav', 'class' => 'mw-jump' ),
+ $skintemplate->getMsg( 'jumpto' )->escaped() . '<a href="#mw-navigation">' . $skintemplate->getMsg( 'jumptonavigation' )->escaped() . '</a>' .
+ $skintemplate->getMsg( 'comma-separator' )->escaped() . '<a href="#p-search">' . $skintemplate->getMsg( 'jumptosearch' )->escaped() . '</a>'
+ );
+
+ $ret .= $this->indent( -1 ) . '</div>';
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildContentBody() {
+ return $this->indent() . IdRegistry::getRegistry()->element( 'div', array( 'id' => 'bodyContent' ),
+ $this->indent( 1 ) . '<!-- body text -->' . "\n" .
+ $this->indent() . $this->getSkinTemplate()->get( 'bodytext' ) .
+ $this->indent() . '<!-- end body text -->' .
+ $this->buildDataAfterContent() .
+ $this->indent( -1 )
+ );
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildCategoryLinks() {
+ // TODO: Category links should be a separate component, but
+ // * dataAfterContent should come after the the category links.
+ // * only one extension is known to use it dataAfterContent and it is geared specifically towards MonoBook
+ // => provide an attribute hideCatLinks for the XML and -if present- hide category links and assume somebody knows what they are doing
+ return
+ $this->indent() . '<!-- category links -->' .
+ $this->indent() . $this->getSkinTemplate()->get( 'catlinks' );
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildDataAfterContent() {
+
+ $skinTemplate = $this->getSkinTemplate();
+
+ if ( $skinTemplate->get( 'dataAfterContent' ) ) {
+ return
+ $this->indent() . '<!-- data blocks which should go somewhere after the body text, but not before the catlinks block-->' .
+ $this->indent() . $skinTemplate->get( 'dataAfterContent' );
+ }
+
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ private function buildMwIndicators() {
+
+ $idRegistry = IdRegistry::getRegistry();
+ $indicators = $this->getSkinTemplate()->get( 'indicators' );
+
+ if ( !is_array( $indicators ) || count( $indicators ) === 0 ) {
+ return '';
+ }
+
+ $this->indent( 1 );
+
+ $ret = '';
+
+ foreach ( $indicators as $id => $content ) {
+ $id = \Sanitizer::escapeId( "mw-indicator-$id" );
+
+ $ret .=
+ $this->indent() .
+ $idRegistry->element( 'div',
+ array(
+ 'id' => $id,
+ 'class' => "mw-indicator $id",
+ ),
+ $content
+ );
+ }
+
+ $ret .= $this->indent( -1 );
+
+ return $ret;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/ContentHeader.php b/www/wiki/skins/chameleon/src/Components/ContentHeader.php
new file mode 100644
index 00000000..724f60da
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/ContentHeader.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * File holding the FooterIcons class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Chameleon
+ */
+
+namespace Skins\Chameleon\Components;
+use Skins\Chameleon\ChameleonTemplate;
+use Skins\Chameleon\IdRegistry;
+
+/**
+ * The FooterIcons class.
+ *
+ * A inline list containing icons: <ul id="footer-icons" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class ContentHeader extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+ global $bannerImage;
+ $skintemplate = $this->getSkinTemplate();
+ $idRegistry = IdRegistry::getRegistry();
+
+ if ($bannerImage) {
+ $ret = $this->indent() . '<div class ="contentHeader bannerimage"><div class="container"><div class="row"><div class="col-lg-12">';
+ } else {
+ $ret = $this->indent() . '<div class ="contentHeader"><div class="container"><div class="row"><div class="col-lg-12">';
+ }
+ $ret .= $this->indent( 1 ) . '<!-- title of the page -->' .
+ $this->indent() . $idRegistry->element( 'h1', array( 'id' => 'firstHeading', 'class' => 'firstHeading' ), $skintemplate->get( 'title' ) ) .
+
+ $this->indent() . '<!-- tagline; usually goes something like "From WikiName" primary purpose of this seems to be for printing to identify the source of the content -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id'=> 'siteSub' ), $skintemplate->getMsg( 'tagline' )->escaped() );
+
+
+ // TODO: Do we need this? Seems to be an accessibility thing. It's used
+ // in vector to jump to the nav which is at the bottom of the document,
+ // but our nav is usually at the top
+ $ret .= $idRegistry->element( 'div', array( 'id' => 'jump-to-nav', 'class' => 'mw-jump' ),
+ $skintemplate->getMsg( 'jumpto' )->escaped() . '<a href="#mw-navigation">' . $skintemplate->getMsg( 'jumptonavigation' )->escaped() . '</a>' .
+ $skintemplate->getMsg( 'comma-separator' )->escaped() . '<a href="#p-search">' . $skintemplate->getMsg( 'jumptosearch' )->escaped() . '</a>'
+ );
+
+ $ret .= $this->indent( -1 ) . '</div></div></div></div>';
+ return $ret;
+
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/FooterIcons.php b/www/wiki/skins/chameleon/src/Components/FooterIcons.php
new file mode 100644
index 00000000..30994304
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/FooterIcons.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * File holding the FooterIcons class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Chameleon
+ */
+
+namespace Skins\Chameleon\Components;
+
+/**
+ * The FooterIcons class.
+ *
+ * A inline list containing icons: <ul id="footer-icons" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class FooterIcons extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = '';
+ $icons = $this->getSkinTemplate()->getFooterIcons( 'icononly' );
+
+ if ( $icons !== null && count( $icons ) > 0 ) {
+
+ $ret = $this->indent() . '<!-- footer icons -->' .
+ $this->indent() . '<ul class="list-inline pull-right footer-icons ' . $this->getClassString() . '" id="footer-icons" >';
+
+ $this->indent( 1 );
+ foreach ( $icons as $blockName => $footerIcons ) {
+
+ $ret .= $this->indent() . '<!-- ' . htmlspecialchars( $blockName ) . ' -->';
+
+ foreach ( $footerIcons as $icon ) {
+ $ret .= $this->indent() . '<li>' .
+ $this->getSkinTemplate()->getSkin()->makeFooterIcon( $icon ) . '</li>';
+ }
+
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' . "\n";
+ }
+
+ return $ret;
+
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/FooterInfo.php b/www/wiki/skins/chameleon/src/Components/FooterInfo.php
new file mode 100644
index 00000000..2d43279d
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/FooterInfo.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * File holding the FooterInfo class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Chameleon
+ */
+
+namespace Skins\Chameleon\Components;
+
+use Skins\Chameleon\ChameleonTemplate;
+use Skins\Chameleon\IdRegistry;
+
+/**
+ * The FooterInfo class.
+ *
+ * An list of footer items (last modified time, view count, number of watching users, credits, copyright)
+ * Does not include so called places (about, privacy policy, and disclaimer links). They need to be added to the page elsewhere.
+ *
+ * This is an unstyled unordered list: <ul id="footer-info" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class FooterInfo extends Component {
+
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+ parent::__construct( $template, $domElement , $indent );
+ $this->addClasses( 'list-unstyled small' );
+ }
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = $this->indent() . '<!-- footer links -->' .
+ $this->indent() .
+ \Html::openElement( 'ul', array(
+ 'class' => 'footer-info ' . $this->getClassString(),
+ 'id' => IdRegistry::getRegistry()->getId( 'footer-info' ),
+ )
+ );
+
+ $footerlinks = $this->getSkinTemplate()->getFooterLinks();
+ $this->indent( 1 );
+ foreach ( $footerlinks as $category => $links ) {
+ if ( $category !== 'places' ) {
+
+ $ret .= $this->indent() . '<!-- ' . htmlspecialchars( $category ) . ' -->';
+ foreach ( $links as $key ) {
+ $ret .= $this->indent() . '<li>' . $this->getSkinTemplate()->get( $key ) . '</li>';
+ }
+
+ }
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' . "\n";
+
+ return $ret;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/FooterPlaces.php b/www/wiki/skins/chameleon/src/Components/FooterPlaces.php
new file mode 100644
index 00000000..470633ae
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/FooterPlaces.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * File holding the FooterPlaces class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+/**
+ * The FooterInfo class.
+ *
+ * A inline list containing links to places (about, privacy policy, and disclaimer links): <ul id="footer-places">
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class FooterPlaces extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = null;
+ $footerlinks = $this->getSkinTemplate()->getFooterLinks();
+
+ if ( array_key_exists( 'places', $footerlinks ) ) {
+
+ $ret = $this->indent() . '<!-- places -->' .
+ $this->indent() . '<ul class="list-inline footer-places ' . $this->getClassString() . '" id="footer-places">';
+
+ $this->indent( 1 );
+ foreach ( $footerlinks[ 'places' ] as $key ) {
+ $ret .= $this->indent() . '<li><small>' . $this->getSkinTemplate()->get( $key ) . '</small></li>';
+ }
+ $ret .= $this->indent( -1 ) . '</ul>' . "\n";
+ }
+
+ return $ret;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Grid.php b/www/wiki/skins/chameleon/src/Components/Grid.php
new file mode 100644
index 00000000..79c1472c
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Grid.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * File holding the Grid class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Skins\Chameleon\ChameleonTemplate;
+
+/**
+ * The Grid class.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Grid extends Container {
+
+ const ATTR_MODE = 'mode';
+ const MODE_FIXEDWIDTH = 'fixedwidth';
+ const MODE_FLUID = 'fluid';
+
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+
+ parent::__construct( $template, $domElement, $indent );
+
+ if( $this->isFluidMode() ) {
+ $this->addClasses( 'container-fluid' );
+ } else {
+ $this->addClasses( 'container' );
+ }
+ }
+
+ protected function isFluidMode() {
+ return $this->getAttribute( self::ATTR_MODE, self::MODE_FIXEDWIDTH ) === self::MODE_FLUID;
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/Html.php b/www/wiki/skins/chameleon/src/Components/Html.php
new file mode 100644
index 00000000..9297669e
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Html.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * File holding the Html class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+/**
+ * The Html class.
+ *
+ * This component allows insertion of raw HTML into the page.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Html extends Component {
+
+ /**
+ * Builds the HTML code for the main container
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = '';
+
+ if ( $this->getDomElement() !== null ) {
+
+ $dom = $this->getDomElement()->ownerDocument;
+
+ foreach ( $this->getDomElement()->childNodes as $node ) {
+ $ret .= $dom->saveHTML( $node );
+ }
+ }
+
+ return $ret;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/LastmodInfo.php b/www/wiki/skins/chameleon/src/Components/LastmodInfo.php
new file mode 100644
index 00000000..29ef8d4c
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/LastmodInfo.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * File holding the LastmodInfo class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Chameleon
+ */
+
+namespace Skins\Chameleon\Components;
+
+use Skins\Chameleon\ChameleonTemplate;
+use Skins\Chameleon\IdRegistry;
+
+/**
+ * The LastmodInfo class.
+ *
+ * An list of footer items (last modified time, view count, number of watching users, credits, copyright)
+ * Does not include so called places (about, privacy policy, and disclaimer links). They need to be added to the page elsewhere.
+ *
+ * This is an unstyled unordered list: <ul id="footer-info" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class LastmodInfo extends Component {
+
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+ parent::__construct( $template, $domElement , $indent );
+ $this->addClasses( 'list-unstyled small' );
+ }
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = $this->indent() . '<!-- footer links -->' .
+ $this->indent() .
+ \Html::openElement( 'ul', array(
+ 'class' => 'lastmod-info ' . $this->getClassString(),
+ 'id' => IdRegistry::getRegistry()->getId( 'lastmod-info' ),
+ )
+ );
+
+ $footerlinks = $this->getSkinTemplate()->getFooterLinks();
+ $this->indent( 1 );
+ foreach ( $footerlinks as $category => $links ) {
+ if ( $category !== 'places' ) {
+
+ $ret .= $this->indent() . '<!-- ' . htmlspecialchars( $category ) . ' -->';
+ foreach ( $links as $key ) {
+ if ( $key !== 'copyright' ) {
+ $ret .= $this->indent() . '<li>' . $this->getSkinTemplate()->get( $key ) . '</li>';
+ }
+ }
+
+ }
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' . "\n";
+
+ return $ret;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/LegalInfo.php b/www/wiki/skins/chameleon/src/Components/LegalInfo.php
new file mode 100644
index 00000000..c302b624
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/LegalInfo.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * File holding the LegalInfo class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Chameleon
+ */
+
+namespace Skins\Chameleon\Components;
+
+use Skins\Chameleon\ChameleonTemplate;
+use Skins\Chameleon\IdRegistry;
+
+/**
+ * The LegalInfo class.
+ *
+ * An list of footer items (last modified time, view count, number of watching users, credits, copyright)
+ * Does not include so called places (about, privacy policy, and disclaimer links). They need to be added to the page elsewhere.
+ *
+ * This is an unstyled unordered list: <ul id="footer-info" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class LegalInfo extends Component {
+
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+ parent::__construct( $template, $domElement , $indent );
+ $this->addClasses( 'list-unstyled small' );
+ }
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = $this->indent() . '<!-- footer links -->' .
+ $this->indent() .
+ \Html::openElement( 'ul', array(
+ 'class' => 'footer-legal-info ' . $this->getClassString(),
+ 'id' => IdRegistry::getRegistry()->getId( 'footer-legal-info' ),
+ )
+ );
+
+ $footerlinks = $this->getSkinTemplate()->getFooterLinks();
+ $this->indent( 1 );
+ foreach ( $footerlinks as $category => $links ) {
+ if ( $category !== 'places' ) {
+
+ $ret .= $this->indent() . '<!-- ' . htmlspecialchars( $category ) . ' -->';
+ foreach ( $links as $key ) {
+ if ( $key == 'copyright' ) {
+ $ret .= $this->indent() . '<li>' . $this->getSkinTemplate()->get( $key ) . '</li>';
+ }
+ }
+
+ }
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' . "\n";
+
+ return $ret;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Logo.php b/www/wiki/skins/chameleon/src/Components/Logo.php
new file mode 100644
index 00000000..be592ed2
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Logo.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * File holding the Logo class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2016, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Logo class.
+ *
+ * The logo image as a link to the wiki main page wrapped in a div: <div id="p-logo" role="banner">
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Logo extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $attribs = NULL;
+ if ( $this->addLink() ) {
+ $attribs = array_merge(
+ array( 'href' => $this->getSkinTemplate()->data[ 'nav_urls' ][ 'mainpage' ][ 'href' ] ),
+ Linker::tooltipAndAccesskeyAttribs( 'p-logo' )
+ );
+ }
+
+ $contents = \Html::element( 'img',
+ array(
+ 'src' => $this->getSkinTemplate()->data[ 'logopath' ],
+ 'alt' => $this->getSkinTemplate()->data[ 'sitename' ],
+ )
+ );
+
+ return
+ $this->indent() . '<!-- logo and main page link -->' .
+ $this->indent() . \Html::openElement( 'div',
+ array(
+ 'id' => IdRegistry::getRegistry()->getId( 'p-logo' ),
+ 'class' => 'p-logo ' . $this->getClassString(),
+ 'role' => 'banner'
+ )
+ ) .
+ $this->indent( 1 ) . \Html::rawElement( 'a', $attribs, $contents ) .
+ $this->indent( -1 ) . '</div>' . "\n";
+ }
+
+ /**
+ * Return true if addLink attribute is unset or set to 'yes' in the Logo
+ * component description. Clicking on the logo should redirect to Main Page
+ * in that case. Else the logo should just display an inactive image.
+ *
+ * @return bool
+ */
+ private function addLink() {
+ if ( $this->getDomElement() === null ) {
+ return true;
+ }
+
+ $addLink = $this->getDomElement()->getAttribute( 'addLink' );
+
+ if ( $addLink === '' ) {
+ return true;
+ }
+
+ return filter_var( $addLink, FILTER_VALIDATE_BOOLEAN );
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/MainContent.php b/www/wiki/skins/chameleon/src/Components/MainContent.php
new file mode 100644
index 00000000..c732bd24
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/MainContent.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * File holding the MainContent class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2016, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Skins\Chameleon\IdRegistry;
+
+/**
+ * The MainContent class.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class MainContent extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $skintemplate = $this->getSkinTemplate();
+ $idRegistry = IdRegistry::getRegistry();
+
+ // START content
+ $ret =
+ $this->indent() . '<!-- start the content area -->' .
+ $this->indent() . $idRegistry->openElement( 'div',
+ array( 'id' => 'content', 'class' => 'mw-body ' . $this->getClassString() )
+ ) .
+
+ $idRegistry->element( 'a', array( 'id' => 'top' ) ) .
+ $this->indent(1) . $idRegistry->element( 'div', array( 'id' => 'mw-indicators', 'class' => 'mw-indicators', ), $this->buildMwIndicators() ) .
+
+ $this->indent() . '<div ' . \Html::expandAttributes( array(
+ 'id' => $idRegistry->getId( 'mw-js-message' ),
+ 'style' => 'display:none;'
+ )
+ ) . $skintemplate->get( 'userlangattributes' ) . '></div>';
+
+ $ret .= $this->buildContentHeader();
+
+ // if ( $skintemplate->get( 'subtitle' ) ) {
+
+ // TODO: should not use class 'small', better use class 'contentSub' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- subtitle line; used for various things like the subpage hierarchy -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub', 'class' => 'small' ), $skintemplate->get( 'subtitle' ) );
+
+ // }
+
+ if ( $skintemplate->get( 'undelete' ) ) {
+ // TODO: should not use class 'small', better use class 'contentSub2' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- undelete message -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub2', 'class' => 'small' ), $skintemplate->get( 'undelete' ) );
+ }
+
+
+ $ret .= $this->buildContentBody();
+ $ret .= $this->buildCategoryLinks();
+
+ $ret .= $this->indent( -1 ) . '</div>';
+ // END content
+
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildContentHeader() {
+
+ $skintemplate = $this->getSkinTemplate();
+ $idRegistry = IdRegistry::getRegistry();
+
+ $ret = $this->indent() . '<div class ="contentHeader">' .
+
+ $this->indent( 1 ) . '<!-- title of the page -->' .
+ $this->indent() . $idRegistry->element( 'h1', array( 'id' => 'firstHeading', 'class' => 'firstHeading' ), $skintemplate->get( 'title' ) ) .
+
+ $this->indent() . '<!-- tagline; usually goes something like "From WikiName" primary purpose of this seems to be for printing to identify the source of the content -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id'=> 'siteSub' ), $skintemplate->getMsg( 'tagline' )->escaped() );
+
+ if ( $skintemplate->get( 'subtitle' ) ) {
+
+ // TODO: should not use class 'small', better use class 'contentSub' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- subtitle line; used for various things like the subpage hierarchy -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub', 'class' => 'small' ), $skintemplate->get( 'subtitle' ) );
+
+ }
+
+ if ( $skintemplate->get( 'undelete' ) ) {
+ // TODO: should not use class 'small', better use class 'contentSub2' and do styling in a less file
+ $ret .=
+ $this->indent() . '<!-- undelete message -->' .
+ $this->indent() . $idRegistry->element( 'div', array( 'id' => 'contentSub2', 'class' => 'small' ), $skintemplate->get( 'undelete' ) );
+ }
+
+ // TODO: Do we need this? Seems to be an accessibility thing. It's used
+ // in vector to jump to the nav which is at the bottom of the document,
+ // but our nav is usually at the top
+ $ret .= $idRegistry->element( 'div', array( 'id' => 'jump-to-nav', 'class' => 'mw-jump' ),
+ $skintemplate->getMsg( 'jumpto' )->escaped() . '<a href="#mw-navigation">' . $skintemplate->getMsg( 'jumptonavigation' )->escaped() . '</a>' .
+ $skintemplate->getMsg( 'comma-separator' )->escaped() . '<a href="#p-search">' . $skintemplate->getMsg( 'jumptosearch' )->escaped() . '</a>'
+ );
+
+ $ret .= $this->indent( -1 ) . '</div>';
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildContentBody() {
+ return $this->indent() . IdRegistry::getRegistry()->element( 'div', array( 'id' => 'bodyContent' ),
+ $this->indent( 1 ) . '<!-- body text -->' . "\n" .
+ $this->indent() . $this->getSkinTemplate()->get( 'bodytext' ) .
+ $this->indent() . '<!-- end body text -->' .
+ $this->buildDataAfterContent() .
+ $this->indent( -1 )
+ );
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildCategoryLinks() {
+ // TODO: Category links should be a separate component, but
+ // * dataAfterContent should come after the the category links.
+ // * only one extension is known to use it dataAfterContent and it is geared specifically towards MonoBook
+ // => provide an attribute hideCatLinks for the XML and -if present- hide category links and assume somebody knows what they are doing
+ return
+ $this->indent() . '<!-- category links -->' .
+ $this->indent() . $this->getSkinTemplate()->get( 'catlinks' );
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildDataAfterContent() {
+
+ $skinTemplate = $this->getSkinTemplate();
+
+ if ( $skinTemplate->get( 'dataAfterContent' ) ) {
+ return
+ $this->indent() . '<!-- data blocks which should go somewhere after the body text, but not before the catlinks block-->' .
+ $this->indent() . $skinTemplate->get( 'dataAfterContent' );
+ }
+
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ private function buildMwIndicators() {
+
+ $idRegistry = IdRegistry::getRegistry();
+ $indicators = $this->getSkinTemplate()->get( 'indicators' );
+
+ if ( !is_array( $indicators ) || count( $indicators ) === 0 ) {
+ return '';
+ }
+
+ $this->indent( 1 );
+
+ $ret = '';
+
+ foreach ( $indicators as $id => $content ) {
+ $id = \Sanitizer::escapeId( "mw-indicator-$id" );
+
+ $ret .=
+ $this->indent() .
+ $idRegistry->element( 'div',
+ array(
+ 'id' => $id,
+ 'class' => "mw-indicator $id",
+ ),
+ $content
+ );
+ }
+
+ $ret .= $this->indent( -1 );
+
+ return $ret;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Menu.php b/www/wiki/skins/chameleon/src/Components/Menu.php
new file mode 100644
index 00000000..86ae5831
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Menu.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * File holding the Menu component class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Sanitizer;
+use Skins\Chameleon\Menu\MenuFactory;
+
+/**
+ * Class Menu
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Menu extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ if ( $this->getDomElement() === null ) {
+ return '';
+ }
+
+ $menu = $this->getMenu();
+
+ $menu->setMenuItemFormatter( function ( $href, $text, $depth, $subitems ) {
+ $href = Sanitizer::cleanUrl( $href );
+ $text = htmlspecialchars( $text );
+ if ( $depth === 1 && !empty( $subitems ) ) {
+ return "<li class=\"dropdown\"><a class=\"dropdown-toggle\" href=\"#\" data-toggle=\"dropdown\">$text<b class=\"caret\"></b></a>$subitems</li>";
+ } else {
+ return "<li><a href=\"$href\">$text</a>$subitems</li>";
+ }
+ } );
+
+ $menu->setItemListFormatter( function ( $rawItemsHtml, $depth ) {
+ if ( $depth === 0 ) {
+ return $rawItemsHtml;
+ } elseif ( $depth === 1 ) {
+ return "<ul class=\"dropdown-menu\">$rawItemsHtml</ul>";
+ } else {
+ return "<ul>$rawItemsHtml</ul>";
+ }
+
+ } );
+
+ return $menu->getHtml();
+ }
+
+ /**
+ * @return \Skins\Chameleon\Menu\Menu
+ */
+ public function getMenu() {
+
+ $domElement = $this->getDomElement();
+ $msgKey = $domElement->getAttribute( 'message' );
+
+ $menuFactory = new MenuFactory();
+
+ if ( empty( $msgKey ) ) {
+ return $menuFactory->getMenuFromMessageText( $domElement->textContent );
+ } else {
+ return $menuFactory->getMenuFromMessage( $msgKey );
+
+ }
+
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Modifications/HideFor.php b/www/wiki/skins/chameleon/src/Components/Modifications/HideFor.php
new file mode 100644
index 00000000..58d78a6c
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Modifications/HideFor.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * File containing the HideFor class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\Modifications;
+use Skins\Chameleon\Components\Silent;
+use Skins\Chameleon\PermissionsHelper;
+
+/**
+ * HideFor class
+ *
+ * @author Stephan Gambke
+ * @since 1.1
+ * @ingroup Skins
+ */
+class HideFor extends Modification {
+
+ private $permissionsHelper;
+
+ /**
+ * This method checks if the restriction is applicable and if necessary
+ * replaces the decorated component by a Silent component
+ */
+ protected function applyModification() {
+ if ( $this->isHidden() ) {
+ $c = $this->getComponent();
+ $this->setComponent( new Silent( $c->getSkinTemplate(), $c->getDomElement(), $c->getIndent() ) );
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ private function isHidden() {
+ $p = $this->getPermissionsHelper();
+ return $p->userHasGroup( 'group' ) && $p->userHasPermission( 'permission' ) && $p->pageIsInNamespace( 'namespace' ) && $p->pageHasCategory( 'category' );
+ }
+
+ /**
+ * @return PermissionsHelper
+ */
+ private function getPermissionsHelper() {
+ if ( $this->permissionsHelper === null ) {
+ $this->permissionsHelper = new PermissionsHelper( $this->getSkinTemplate()->getSkin(), $this->getDomElementOfModification(), true );
+ }
+
+ return $this->permissionsHelper;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Modifications/Modification.php b/www/wiki/skins/chameleon/src/Components/Modifications/Modification.php
new file mode 100644
index 00000000..5fd34b19
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Modifications/Modification.php
@@ -0,0 +1,174 @@
+<?php
+/**
+ * File containing the Modification class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\Modifications;
+
+use Skins\Chameleon\ChameleonTemplate;
+use Skins\Chameleon\Components\Component;
+
+/**
+ * Modification class
+ *
+ * This is the abstract base class of all modifications.
+ *
+ * Follows the Decorator pattern (Decorator role).
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+abstract class Modification extends Component {
+
+ private $component = null;
+
+ /**
+ * @param Component $component
+ * @param \DOMElement $domElement
+ */
+ public function __construct( Component $component, \DOMElement $domElement = null ) {
+
+ $this->component = $component;
+ parent::__construct( $component->getSkinTemplate(), $domElement, $component->getIndent() );
+ }
+
+ /**
+ * This method should apply any modifications to the decorated component
+ * available from the getComponent() method.
+ */
+ abstract protected function applyModification();
+
+ /**
+ * @return \DOMElement|null
+ */
+ public function getDomElementOfModification() {
+ return parent::getDomElement();
+ }
+
+ /**
+ * @return \DOMElement
+ */
+ public function getDomElementOfComponent() {
+ return $this->getDomElement();
+ }
+
+ /**
+ * Sets the class string that should be assigned to the top-level html element of this component
+ *
+ * @param string | array | null $classes
+ *
+ */
+ public function setClasses( $classes ) {
+ $this->getComponent()->setClasses( $classes );
+ }
+
+ /**
+ * @return Component
+ */
+ public function getComponent() {
+ return $this->component;
+ }
+
+ /**
+ * @param Component $component
+ * @since 1.1
+ */
+ protected function setComponent( Component $component ) {
+ $this->component = $component;
+ }
+
+ /**
+ * Adds the given class to the class string that should be assigned to the top-level html element of this component
+ *
+ * @param string | array | null $classes
+ *
+ * @return string | array
+ */
+ public function addClasses( $classes ) {
+ $this->getComponent()->addClasses( $classes );
+ }
+
+ /**
+ * @return ChameleonTemplate
+ */
+ public function getSkinTemplate() {
+ return $this->getComponent()->getSkinTemplate();
+ }
+
+ /**
+ * Returns the current indentation level
+ *
+ * @return int
+ */
+ public function getIndent() {
+ return $this->getComponent()->getIndent();
+ }
+
+ /**
+ * Returns the class string that should be assigned to the top-level html element of this component
+ *
+ * @return string
+ */
+ public function getClassString() {
+ return $this->getComponent()->getClassString();
+ }
+
+ /**
+ * Removes the given class from the class string that should be assigned to the top-level html element of this component
+ *
+ * @param string | array | null $classes
+ *
+ * @return string
+ */
+ public function removeClasses( $classes ) {
+ $this->getComponent()->removeClasses( $classes );
+ }
+
+ /**
+ * Returns the DOMElement from the description XML file associated with this element.
+ *
+ * @return \DOMElement
+ */
+ public function getDomElement() {
+ return $this->getComponent()->getDomElement();
+ }
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+ $this->applyModification();
+ return $this->getComponent()->getHtml();
+ }
+
+ /**
+ * @return array the resource loader modules needed by this component
+ */
+ public function getResourceLoaderModules() {
+ return $this->getComponent()->getResourceLoaderModules();
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Modifications/ShowOnlyFor.php b/www/wiki/skins/chameleon/src/Components/Modifications/ShowOnlyFor.php
new file mode 100644
index 00000000..7c137d81
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Modifications/ShowOnlyFor.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * File containing the ShowOnlyFor class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\Modifications;
+use Skins\Chameleon\Components\Silent;
+use Skins\Chameleon\PermissionsHelper;
+
+/**
+ * ShowOnlyFor class
+ *
+ * @author Stephan Gambke
+ * @since 1.1
+ * @ingroup Skins
+ */
+class ShowOnlyFor extends Modification {
+
+ private $permissionsHelper;
+
+ /**
+ * This method checks if the restriction is applicable and if necessary
+ * replaces the decorated component by a Silent component
+ */
+ protected function applyModification() {
+ if ( ! $this->isShown() ) {
+ $c = $this->getComponent();
+ $this->setComponent( new Silent( $c->getSkinTemplate(), $c->getDomElement(), $c->getIndent() ) );
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ private function isShown() {
+ $p = $this->getPermissionsHelper();
+ return $p->userHasGroup( 'group' ) || $p->userHasPermission( 'permission' ) || $p->pageIsInNamespace( 'namespace' ) || $p->pageHasCategory( 'category' );
+ }
+
+ /**
+ * @return PermissionsHelper
+ */
+ private function getPermissionsHelper() {
+ if ( $this->permissionsHelper === null ) {
+ $this->permissionsHelper = new PermissionsHelper( $this->getSkinTemplate()->getSkin(), $this->getDomElementOfModification(), false );
+ }
+
+ return $this->permissionsHelper;
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Modifications/Sticky.php b/www/wiki/skins/chameleon/src/Components/Modifications/Sticky.php
new file mode 100644
index 00000000..cbac2107
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Modifications/Sticky.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * File containing the Sticky class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\Modifications;
+
+/**
+ * Class Sticky
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Sticky extends Modification {
+
+ protected function applyModification() {
+ $this->getComponent()->addClasses( 'sticky' );
+ }
+
+ /**
+ * @return string[] the resource loader modules needed by this component
+ */
+ public function getResourceLoaderModules() {
+ $modules = parent::getResourceLoaderModules();
+ $modules[] = 'skin.chameleon.jquery-sticky';
+ return $modules;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/NavMenu.php b/www/wiki/skins/chameleon/src/Components/NavMenu.php
new file mode 100644
index 00000000..65b9aa8f
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavMenu.php
@@ -0,0 +1,221 @@
+<?php
+/**
+ * File holding the NavMenu class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @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' => $this->showTools(), 'languages' => $this->showLanguages()
+ )
+ );
+
+ $flatten = $this->getMenusToBeFlattened();
+
+ // create a dropdown for each sidebar box
+ foreach ( $sidebar as $menuName => $menuDescription ) {
+ $ret .= $this->getDropdownForNavMenu( $menuName, $menuDescription, array_search( $menuName, $flatten ) !== false );
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @return bool
+ */
+ private function showLanguages() {
+ return $this->getDomElement() !== null &&
+ filter_var( $this->getDomElement()->getAttribute( 'showLanguages' ), FILTER_VALIDATE_BOOLEAN );
+ }
+
+ /**
+ * @return bool
+ */
+ private function showTools() {
+ return $this->getDomElement() !== null &&
+ filter_var( $this->getDomElement()->getAttribute( 'showTools' ), FILTER_VALIDATE_BOOLEAN );
+ }
+
+ /**
+ * Create a single dropdown
+ *
+ * @param string $menuName
+ * @param mixed[] $menuDescription
+ * @param bool $flatten
+ *
+ * @return string
+ */
+ protected function getDropdownForNavMenu( $menuName, $menuDescription, $flatten = false ) {
+
+ // open list item containing the dropdown
+ $ret = $this->indent() . '<!-- ' . $menuName . ' -->';
+
+ if ( $flatten ) {
+
+ $ret .= $this->buildMenuItemsForDropdownMenu( $menuDescription );
+
+ } elseif ( !$this->hasSubmenuItems( $menuDescription ) ) {
+
+ $ret .= $this->buildDropdownMenuStub( $menuDescription );
+
+ } else {
+
+ $ret .= $this->buildDropdownOpeningTags( $menuDescription ) .
+ $this->buildMenuItemsForDropdownMenu( $menuDescription, 2 ) .
+ $this->buildDropdownClosingTags();
+
+
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @param mixed[] $menuDescription
+ * @param int $indent
+ *
+ * @return string
+ */
+ protected function buildMenuItemsForDropdownMenu( $menuDescription, $indent = 0 ) {
+
+ // build the list of submenu items
+ if ( $this->hasSubmenuItems( $menuDescription ) ) {
+
+ $menuitems = '';
+ $this->indent( $indent );
+
+ foreach ( $menuDescription['content'] as $key => $item ) {
+ $menuitems .= $this->indent() . $this->getSkinTemplate()->makeListItem( $key, $item );
+ }
+
+ $this->indent( - $indent );
+
+ return $menuitems;
+
+ } else {
+ return $this->indent() . '<!-- empty -->';
+ }
+ }
+
+ /**
+ * @param mixed[] $menuDescription
+ *
+ * @return bool
+ */
+ protected function hasSubmenuItems( $menuDescription ) {
+ return is_array( $menuDescription['content'] ) && count( $menuDescription['content'] ) > 0;
+ }
+
+ /**
+ * @param mixed[] $menuDescription
+ *
+ * @return string
+ */
+ protected function buildDropdownMenuStub( $menuDescription ) {
+ return
+ $this->indent() . \Html::rawElement( 'li',
+ array(
+ 'class' => '',
+ 'title' => Linker::titleAttrib( $menuDescription[ 'id' ] )
+ ),
+ '<a href="#">' . htmlspecialchars( $menuDescription[ 'header' ] ) . '</a>'
+ );
+ }
+
+ /**
+ * @param mixed[] $menuDescription
+ *
+ * @return string
+ */
+ protected function buildDropdownOpeningTags( $menuDescription ) {
+ // open list item containing the dropdown
+ $ret = $this->indent() . \Html::openElement( 'li',
+ array(
+ 'class' => 'dropdown',
+ 'title' => Linker::titleAttrib( $menuDescription['id'] ),
+ ) );
+
+ // add the dropdown toggle
+ $ret .= $this->indent( 1 ) . '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' .
+ htmlspecialchars( $menuDescription['header'] ) . ' <b class="caret"></b></a>';
+
+ // open list of dropdown menu items
+ $ret .= $this->indent() .
+ $this->indent() . \Html::openElement( 'ul',
+ array(
+ 'class' => 'dropdown-menu ' . $menuDescription[ 'id' ],
+ 'id' => IdRegistry::getRegistry()->getId( $menuDescription[ 'id' ] ),
+ )
+ );
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildDropdownClosingTags() {
+ return $this->indent() . '</ul>' . $this->indent( - 1 ) . '</li>';
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getMenusToBeFlattened() {
+ $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();
+ }
+
+ return $flatten;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal.php
new file mode 100644
index 00000000..3694382a
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal.php
@@ -0,0 +1,256 @@
+<?php
+/**
+ * File holding the NavbarHorizontal class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 DOMElement;
+use Skins\Chameleon\IdRegistry;
+
+/**
+ * The NavbarHorizontal class.
+ *
+ * A horizontal navbar containing the sidebar items.
+ * Does not include standard items (toolbox, search, language links). They need
+ * to be added to the page elsewhere
+ *
+ * The navbar is a list of lists wrapped in a nav element: <nav
+ * role="navigation" id="p-navbar" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class NavbarHorizontal extends Component {
+
+ private $mHtml = null;
+ private $htmlId = null;
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ if ( $this->mHtml === null ) {
+ $this->buildHtml();
+ }
+
+ return $this->mHtml;
+ }
+
+ /**
+ *
+ */
+ protected function buildHtml() {
+
+ if ( $this->getDomElement() === null ) {
+ $this->mHtml = '';
+ return;
+ }
+
+ $this->mHtml =
+ $this->buildFixedNavBarIfRequested() .
+ $this->buildNavBarOpeningTags() .
+ $this->buildNavBarComponents() .
+ $this->buildNavBarClosingTags();
+ }
+
+ /**
+ *
+ */
+ protected function buildFixedNavBarIfRequested() {
+ // if a fixed navbar is requested
+ if ( filter_var( $this->getDomElement()->getAttribute( 'fixed' ), FILTER_VALIDATE_BOOLEAN ) === true ||
+ $this->getDomElement()->getAttribute( 'position' ) === 'fixed'
+ ) {
+
+ // first build the actual navbar and set a class so it will be fixed
+ $this->getDomElement()->setAttribute( 'fixed', '0' );
+ $this->getDomElement()->setAttribute( 'position', '' );
+
+ $realNav = new self( $this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() );
+ $realNav->setClasses( $this->getClassString() . ' navbar-fixed-top' );
+
+ // then add an invisible copy of the nav bar that will act as a spacer
+ $this->addClasses( 'navbar-static-top invisible' );
+
+ return $realNav->getHtml();
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildNavBarOpeningTags() {
+ $openingTags =
+ $this->indent() . '<!-- navigation bar -->' .
+ $this->indent() . \Html::openElement( 'nav', array(
+ 'class' => 'navbar navbar-default p-navbar ' . $this->getClassString(),
+ 'role' => 'navigation',
+ 'id' => $this->getHtmlId()
+ )
+ ) .
+ $this->indent( 1 ) . '<div class="container">';
+
+ $this->indent( 1 );
+
+ return $openingTags;
+ }
+
+ /**
+ * @return string
+ */
+ private function getHtmlId() {
+ if ( $this->htmlId === null ) {
+ $this->htmlId = IdRegistry::getRegistry()->getId( 'mw-navigation' );
+ }
+ return $this->htmlId;
+ }
+
+ /**
+ *
+ */
+ protected function buildNavBarComponents() {
+
+ $elements = $this->buildNavBarElementsFromDomTree();
+
+ if ( !empty( $elements[ 'right' ] ) ) {
+
+ $elements[ 'left' ][ ] =
+ $this->indent( 1 ) . '<div class="navbar-right-aligned">' .
+ implode( $elements[ 'right' ] ) .
+ $this->indent() . '</div> <!-- navbar-right-aligned -->';
+
+ $this->indent( -1 );
+ }
+
+ return
+ $this->buildHead( $elements[ 'head' ] ) .
+ $this->buildTail( $elements[ 'left' ] );
+ }
+
+ /**
+ * @return string[][]
+ */
+ protected function buildNavBarElementsFromDomTree() {
+
+ $elements = array(
+ 'head' => array(),
+ 'left' => array(),
+ 'right' => array(),
+ );
+
+ /** @var \DOMElement[] $children */
+ $children = $this->getDomElement()->hasChildNodes() ? $this->getDomElement()->childNodes : array();
+
+ // add components
+ foreach ( $children as $node ) {
+ $this->buildAndCollectNavBarElementFromDomElement( $node, $elements );
+ }
+ return $elements;
+ }
+
+ /**
+ * @param DOMElement $node
+ * @param $elements
+ */
+ protected function buildAndCollectNavBarElementFromDomElement( $node, &$elements ) {
+
+ if ( $node instanceof DOMElement && $node->tagName === 'component' && $node->hasAttribute( 'type' ) ) {
+
+ $position = $node->getAttribute( 'position' );
+
+ if ( !array_key_exists( $position, $elements ) ) {
+ $position = 'left';
+ }
+
+ $indentation = ( $position === 'right' ) ? 2 : 1;
+
+ $this->indent( $indentation );
+ $html = $this->buildNavBarElementFromDomElement( $node );
+ $this->indent( -$indentation );
+
+ $elements[ $position ][ ] = $html;
+
+ // } else {
+ // TODO: Warning? Error?
+ }
+ }
+
+ /**
+ * @param \DomElement $node
+ *
+ * @return string
+ */
+ protected function buildNavBarElementFromDomElement( $node ) {
+ return $this->getSkin()->getComponentFactory()->getComponent( $node, $this->getIndent() )->getHtml();
+ }
+
+ /**
+ * @param string[] $headElements
+ *
+ * @return string
+ */
+ protected function buildHead( $headElements ) {
+
+ $head =
+ $this->indent() . "<div class=\"navbar-header\">\n" .
+ $this->indent( 1 ) . "<button type=\"button\" class=\"navbar-toggle collapsed\" data-toggle=\"collapse\" data-target=\"#" . $this->getHtmlId() . "-collapse\">" .
+ $this->indent( 1 ) . "<span class=\"sr-only\">Toggle navigation</span>" .
+ $this->indent() . str_repeat( "<span class=\"icon-bar\"></span>", 3 ) .
+ $this->indent( -1 ) . "</button>\n" .
+ implode( '', $headElements ) . "\n" .
+ $this->indent( -1 ) . "</div>\n";
+
+ return $head;
+ }
+
+ /**
+ * @param string[] $tailElements
+ *
+ * @return string
+ */
+ protected function buildTail( $tailElements ) {
+
+ return
+ $this->indent() . '<div class="collapse navbar-collapse" id="' . $this->getHtmlId() . '-collapse">' .
+ implode( '', $tailElements ) .
+ $this->indent() . '</div><!-- /.navbar-collapse -->';
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildNavBarClosingTags() {
+ return
+ $this->indent( -1 ) . '</div>' .
+ $this->indent( -1 ) . '</nav>' . "\n";
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Logo.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Logo.php
new file mode 100644
index 00000000..d4e42823
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Logo.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\Logo class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Skins\Chameleon\Components\Component;
+use Skins\Chameleon\Components\Logo as GenLogo;
+
+/**
+ * The NavbarHorizontal\Logo class.
+ *
+ * Provides a Logo component to be included in a NavbarHorizontal component.
+ *
+ * @author Stephan Gambke
+ * @since 1.6
+ * @ingroup Skins
+ */
+class Logo extends Component {
+
+ /**
+ * @return String
+ */
+ public function getHtml() {
+
+ $logo = new GenLogo( $this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() );
+ $logo->addClasses( 'navbar-brand' );
+
+ return $logo->getHtml();
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Menu.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Menu.php
new file mode 100644
index 00000000..e47dca25
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/Menu.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\Menu class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Skins\Chameleon\Components\Component;
+use Skins\Chameleon\Components\Menu as GenMenu;
+
+/**
+ * The NavbarHorizontal\Logo class.
+ *
+ * Provides a Menu component to be included in a NavbarHorizontal component.
+ *
+ * @author Stephan Gambke
+ * @since 1.6
+ * @ingroup Skins
+ */
+class Menu extends Component {
+
+ /**
+ * @return String
+ */
+ public function getHtml() {
+ $menu = new GenMenu( $this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() );;
+ return '<ul class="nav navbar-nav">' . $menu->getHtml() . "</ul>\n";
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/NavMenu.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/NavMenu.php
new file mode 100644
index 00000000..1cc15c28
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/NavMenu.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\NavMenu class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Skins\Chameleon\Components\Component;
+use Skins\Chameleon\Components\NavMenu as GenNavMenu;
+
+/**
+ * The NavbarHorizontal\NavMenu class.
+ *
+ * Provides a NavMenu component to be included in a NavbarHorizontal component.
+ *
+ * @author Stephan Gambke
+ * @since 1.6
+ * @ingroup Skins
+ */
+class NavMenu extends Component {
+
+ /**
+ * @return String
+ */
+ public function getHtml() {
+ $navMenu = new GenNavMenu( $this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() );;
+ return '<ul class="nav navbar-nav">' . $navMenu->getHtml() . "</ul>\n";
+ }
+
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageTools.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageTools.php
new file mode 100644
index 00000000..58776077
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageTools.php
@@ -0,0 +1,159 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\PageTools class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Skins\Chameleon\Components\Component;
+use Skins\Chameleon\Components\PageTools as GenPageTools;
+
+/**
+ * The NavbarHorizontal\PageTools class.
+ *
+ * Provides a PageTools component to be included in a NavbarHorizontal component.
+ *
+ * @author Stephan Gambke
+ * @since 1.6
+ * @ingroup Skins
+ */
+class PageTools extends Component {
+
+ /**
+ * @return String
+ */
+ public function getHtml() {
+
+ $ret = '';
+
+ $pageTools = new GenPageTools( $this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() + 1 );
+
+ $pageTools->setFlat( true );
+ $pageTools->removeClasses( 'text-center list-inline' );
+ $pageTools->addClasses( 'dropdown-menu' );
+
+ $editLinkHtml = $this->getEditLinkHtml( $pageTools );
+
+ $pageToolsHtml = $pageTools->getHtml();
+
+ if ( $editLinkHtml || $pageToolsHtml ) {
+ $ret =
+ $this->indent() . '<!-- page tools -->' .
+ $this->indent() . '<ul class="navbar-tools navbar-nav" >';
+
+ if ( $editLinkHtml !== '' ) {
+ $ret .= $this->indent( 1 ) . $editLinkHtml;
+ }
+
+ if ( $pageToolsHtml !== '' ) {
+ $ret .=
+ $this->indent( $editLinkHtml !== '' ? 0 : 1 ) . '<li class="navbar-tools-tools dropdown">' .
+ $this->indent( 1 ) . '<a data-toggle="dropdown" class="dropdown-toggle" href="#" title="' . $this->getSkinTemplate()->getMsg( 'specialpages-group-pagetools' )->text() . '" ><span>...</span></a>' .
+ $pageToolsHtml .
+ $this->indent( -1 ) . '</li>';
+ }
+ $ret .=
+ $this->indent( $editLinkHtml !== '' ? 0 : -1 ) . '</ul>' . "\n";
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @param GenPageTools $pageTools
+ * @return string
+ */
+ protected function getEditLinkHtml( $pageTools ) {
+
+ $pageToolsStructure = $pageTools->getPageToolsStructure();
+
+ if ( ! array_key_exists( 'views', $pageToolsStructure ) ) {
+ return '';
+ }
+
+ foreach ( $this->getReplaceableEditActionIds() as $id ) {
+
+ if ( array_key_exists( $id, $pageToolsStructure[ 'views' ] ) ) {
+ return $this->getLinkAndRemoveFromPageToolStructure( $pageTools, $id );
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param GenPageTools $pageTools
+ * @param string $editActionId
+ *
+ * @return string
+ */
+ protected function getLinkAndRemoveFromPageToolStructure( $pageTools, $editActionId ) {
+
+ $pageToolsStructure = $pageTools->getPageToolsStructure();
+ $editActionStructure = $pageToolsStructure[ 'views' ][ $editActionId ];
+
+ $editActionStructure[ 'text' ] = '';
+
+ if ( array_key_exists( 'class', $editActionStructure ) ) {
+ $editActionStructure[ 'class' ] .= ' navbar-tools-tools';
+ } else {
+ $editActionStructure[ 'class' ] = 'navbar-tools-tools';
+ }
+
+ $options = array (
+ 'text-wrapper' => array(
+ 'tag' => 'span',
+ 'attributes' => array('class' => 'glyphicon glyphicon-pencil',)
+ ),
+ );
+
+ $editLinkHtml = $this->getSkinTemplate()->makeListItem(
+ $editActionId,
+ $editActionStructure,
+ $options
+ );
+
+ $pageTools->setRedundant( $editActionId );
+
+ return $editLinkHtml;
+ }
+
+ /**
+ * @return string[]
+ */
+ protected function getReplaceableEditActionIds() {
+
+ $editActionIds = array( 've-edit', 'edit' );
+
+ if ( array_key_exists( 'sfgRenameEditTabs', $GLOBALS ) && $GLOBALS[ 'sfgRenameEditTabs' ] === true ||
+ array_key_exists( 'wgPageFormsRenameEditTabs', $GLOBALS ) && $GLOBALS[ 'wgPageFormsRenameEditTabs' ] === true ) {
+
+ $editActionIds = array_merge( array( 'formedit', 'form_edit' ), $editActionIds );
+ }
+
+ return $editActionIds;
+ }
+
+
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageToolsAdaptable.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageToolsAdaptable.php
new file mode 100644
index 00000000..e82e2ada
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PageToolsAdaptable.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\PageToolsAdaptable class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Skins\Chameleon\Components\PageTools as GenPageTools;
+
+/**
+ * The NavbarHorizontal\PageToolsAdaptable class.
+ *
+ * Provides an adaptable PageTools component to be included in a NavbarHorizontal component.
+ *
+ * @author Tobias Oetterer
+ * @since 1.6
+ * @ingroup Skins
+ */
+class PageToolsAdaptable extends PageTools
+{
+
+ const GLYPH_ICON_UNKNOWN_ACTION = 'asterisk';
+
+ /**
+ * @var string[]
+ */
+ private $mShowActions = null;
+
+ /**
+ * @var string[]
+ */
+ private $mValidActionsToShow = null;
+
+ /**
+ * @var array
+ */
+ private static $sGlyphIconForAction = array(
+ 'delete' => 'trash',
+ 'edit' => 'edit',
+ 'formedit' => 'list-alt',
+ 'history' => 'education',
+ 'move' => 'share-alt',
+ 'protect' => 'folder-close',
+ 'purge' => 'repeat',
+ 'undelete' => 'road',
+ 'unprotect' => 'folder-open',
+ 'unwatch' => 'star',
+ 've-edit' => 'pencil',
+ 'view' => 'eye-open',
+ 'watch' => 'star-empty',
+ );
+
+ /**
+ * @param string $action
+ * @param string $fallback
+ * @return null|string
+ */
+ public static function getGlyphIconForAction( $action, $fallback = null ) {
+ if ( isset( self::$sGlyphIconForAction[$action] ) ) {
+ return self::$sGlyphIconForAction[$action];
+ }
+ return $fallback !== null ? $fallback : self::GLYPH_ICON_UNKNOWN_ACTION;
+ }
+
+ /**
+ * @param string $icon
+ * @param string $action
+ */
+ public static function setGlyphIconForAction( $icon, $action ) {
+ if ( is_string( $icon ) && $icon && is_string( $action ) && $action ) {
+ self::$sGlyphIconForAction[$action] = $icon;
+ }
+ }
+
+ /**
+ * @param GenPageTools $pageTools
+ * @return string
+ * @throws \MWException
+ */
+ protected function getEditLinkHtml( $pageTools ) {
+
+ $pageToolsStructure = $pageTools->getPageToolsStructure();
+ if ( !array_key_exists( 'views', $pageToolsStructure ) ) {
+ return '';
+ }
+
+ $items = array();
+
+ $showActions = $this->getShowActions( $pageTools );
+
+ foreach ( $showActions as $actionId ) {
+
+ if ( array_key_exists( $actionId, $pageToolsStructure['views'] ) ) {
+ $items[] = $this->getLinkAndRemoveFromPageToolStructure( $pageTools, $actionId );
+ }
+ }
+
+ return implode(
+ $this->indent() . '</ul>' . $this->indent() . '<ul class="navbar-tools navbar-nav" >' . $this->indent() . "\t",
+ $items
+ );
+ }
+
+ /**
+ * @param string $action
+ * @return string
+ */
+ protected function getGlyphIconClassFor( $action ) {
+ return 'glyphicon glyphicon-' . self::getGlyphIconForAction( $action );
+ }
+
+ /**
+ * @param GenPageTools $pageTools
+ * @param string $editActionId
+ *
+ * @return string
+ */
+ protected function getLinkAndRemoveFromPageToolStructure( $pageTools, $editActionId ) {
+
+ $pageToolsStructure = $pageTools->getPageToolsStructure();
+ $editActionStructure = $pageToolsStructure['views'][$editActionId];
+
+ $editActionStructure['text'] = '';
+
+ if ( array_key_exists( 'class', $editActionStructure ) ) {
+ $editActionStructure['class'] .= ' navbar-tools-tools';
+ } else {
+ $editActionStructure['class'] = 'navbar-tools-tools';
+ }
+
+ $options = array(
+ 'text-wrapper' => array(
+ 'tag' => 'span',
+ 'attributes' => array( 'class' => $this->getGlyphIconClassFor( $editActionId ), ),
+ ),
+ );
+
+ $editLinkHtml = $this->getSkinTemplate()->makeListItem(
+ $editActionId,
+ $editActionStructure,
+ $options
+ );
+
+ $pageTools->setRedundant( $editActionId );
+
+ return $editLinkHtml;
+ }
+
+ /**
+ * @param @param GenPageTools $pageTools
+ * @return string[]|null
+ */
+ protected function getShowActions( $pageTools ) {
+ if ( $this->mShowActions !== null ) {
+ return $this->mShowActions;
+ }
+ $showActions = array();
+
+ $showAttributesString = $this->getDomElement() !== null ? $this->getDomElement()->getAttribute( 'show' ) : '';
+
+ if ( $showAttributesString != '' ) {
+ foreach ( explode( ',', $showAttributesString ) as $requestedShowAction ) {
+ if ( in_array( $requestedShowAction, $this->getValidActionsToShow( $pageTools ) ) ) {
+ $showActions[] = $requestedShowAction;
+ }
+ }
+ }
+ return $this->mShowActions = $showActions;
+ }
+
+ /**
+ * @param GenPageTools $pageTools
+ * @return string[]
+ */
+ protected function getValidActionsToShow( $pageTools ) {
+ if ( $this->mValidActionsToShow !== null ) {
+ return $this->mValidActionsToShow;
+ }
+ $pageToolsStructure = $pageTools->getPageToolsStructure();
+ $validActionsToShow = array();
+
+ foreach ( $pageToolsStructure as $group => $groupStructure ) {
+ $validActionsToShow = array_merge( $validActionsToShow, array_keys( $groupStructure ) );
+ }
+ return $this->mValidActionsToShow = $validActionsToShow;
+ }
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PersonalTools.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PersonalTools.php
new file mode 100644
index 00000000..540e10d0
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/PersonalTools.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\PersonalTools class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Hooks;
+use Skins\Chameleon\Components\Component;
+
+/**
+ * The NavbarHorizontal\PersonalTools class.
+ *
+ * Provides a PersonalTools component to be included in a NavbarHorizontal component.
+ *
+ * @author Stephan Gambke
+ * @since 1.6
+ * @ingroup Skins
+ */
+class PersonalTools extends Component {
+
+ /**
+ * @return String
+ */
+ public function getHtml() {
+
+ $user = $this->getSkinTemplate()->getSkin()->getUser();
+
+ if ( $user->isLoggedIn() ) {
+ $toolsClass = 'navbar-userloggedin';
+ $toolsLinkText = $this->getSkinTemplate()->getMsg( 'chameleon-loggedin' )->params( $user->getName() )->text();
+ } else {
+ $toolsClass = 'navbar-usernotloggedin';
+ $toolsLinkText = $this->getSkinTemplate()->getMsg( 'chameleon-notloggedin' )->text();
+ }
+
+ $linkText = '<span class="glyphicon glyphicon-user"></span>';
+ \Hooks::run('ChameleonNavbarHorizontalPersonalToolsLinkText', array( &$linkText, $this->getSkin() ) );
+
+ // start personal tools element
+ $ret =
+ $this->indent() . '<!-- personal tools -->' .
+ $this->indent() . '<ul class="'.$this->getClassString().' navbar-tools navbar-nav" >' .
+ $this->indent( 1 ) . '<li class="dropdown navbar-tools-tools">' .
+ $this->indent( 1 ) . '<a class="dropdown-toggle ' . $toolsClass . '" href="#" data-toggle="dropdown" title="' . $toolsLinkText . '" >' . $linkText . '</a>' .
+ $this->indent() . '<ul class="p-personal-tools dropdown-menu dropdown-menu-right" >';
+
+ $this->indent( 1 );
+
+ // add personal tools (links to user page, user talk, prefs, ...)
+ foreach ( $this->getSkinTemplate()->getPersonalTools() as $key => $item ) {
+ $ret .= $this->indent() . $this->getSkinTemplate()->makeListItem( $key, $item );
+ }
+
+ $ret .=
+ $this->indent( -1 ) . '</ul>' .
+ $this->indent( -1 ) . '</li>';
+
+ // if the user is logged in, add the newtalk notifier
+ if ( $user->isLoggedIn() ) {
+
+ $newMessagesAlert = '';
+ $newtalks = $user->getNewMessageLinks();
+ $out = $this->getSkinTemplate()->getSkin()->getOutput();
+
+ // Allow extensions to disable the new messages alert;
+ // since we do not display the link text, we ignore the actual value returned in $newMessagesAlert
+ if ( Hooks::run( 'GetNewMessagesAlert', array( &$newMessagesAlert, $newtalks, $user, $out ) ) ) {
+
+ if ( count( $user->getNewMessageLinks() ) > 0 ) {
+ $newtalkClass = 'navbar-newtalk-available';
+ $newtalkLinkText = $this->getSkinTemplate()->getMsg( 'chameleon-newmessages' )->text();
+ } else {
+ $newtalkClass = 'navbar-newtalk-not-available';
+ $newtalkLinkText = $this->getSkinTemplate()->getMsg( 'chameleon-nonewmessages' )->text();
+ }
+
+ $linkText = '<span class="glyphicon glyphicon-envelope"></span>';
+ \Hooks::run('ChameleonNavbarHorizontalNewTalkLinkText', array( &$linkText, $this->getSkin() ) );
+
+ $ret .= $this->indent() . '<li class="navbar-newtalk-notifier">' .
+ $this->indent( 1 ) . '<a class="dropdown-toggle ' . $newtalkClass . '" title="' .
+ $newtalkLinkText . '" href="' . $user->getTalkPage()->getLinkURL( 'redirect=no' ) . '">' . $linkText . '</a>' .
+ $this->indent( -1 ) . '</li>';
+
+ }
+
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' . "\n";
+
+ return $ret;
+ }
+
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/SearchBar.php b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/SearchBar.php
new file mode 100644
index 00000000..d665b2d9
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NavbarHorizontal/SearchBar.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * File holding the NavbarHorizontal\PersonalTools class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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\NavbarHorizontal;
+
+use Skins\Chameleon\Components\Component;
+use Skins\Chameleon\Components\SearchBar as GenericSearchBar;
+
+/**
+ * The NavbarHorizontal\PersonalTools class.
+ *
+ * Provides a SearchBar component to be included in a NavbarHorizontal component.
+ *
+ * @author Stephan Gambke
+ * @since 1.6
+ * @ingroup Skins
+ */
+class SearchBar extends Component {
+
+ /**
+ * @return String
+ */
+ public function getHtml() {
+
+ $search = new GenericSearchBar( $this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() );
+ $search->addClasses( 'navbar-form' );
+
+ return $search->getHtml();
+ }
+
+
+} \ No newline at end of file
diff --git a/www/wiki/skins/chameleon/src/Components/NewtalkNotifier.php b/www/wiki/skins/chameleon/src/Components/NewtalkNotifier.php
new file mode 100644
index 00000000..d9f6cf76
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/NewtalkNotifier.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * File holding the NewtalkNotifier class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+/**
+ * The NewtalkNotifier class.
+ *
+ * A message to a user about new messages on their talkpage
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class NewtalkNotifier extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $data = $this->getSkinTemplate()->data;
+
+ if ( array_key_exists( 'newtalk', $data ) && $data[ 'newtalk' ] ) {
+ return $this->indent() . '<!-- message to a user about new messages on their talkpage -->' .
+ $this->indent() . '<span class="usermessage ' . $this->getClassString() . '">' . $this->getSkinTemplate()->data[ 'newtalk' ] . '</span>';
+ } else {
+ return '';
+ }
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/PageTools.php b/www/wiki/skins/chameleon/src/Components/PageTools.php
new file mode 100644
index 00000000..56ca3a0d
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/PageTools.php
@@ -0,0 +1,267 @@
+<?php
+/**
+ * File holding the PageTools class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Action;
+use MWNamespace;
+use Skins\Chameleon\ChameleonTemplate;
+use Skins\Chameleon\IdRegistry;
+
+/**
+ * The PageTools class.
+ *
+ * A unordered list containing content navigation links (Page, Discussion,
+ * Edit, History, Move, ...)
+ *
+ * The tab list is a list of lists: '<ul id="p-contentnavigation">
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class PageTools extends Component {
+
+ private $mFlat = false;
+ private $mPageToolsStructure = null;
+
+ /**
+ * @param ChameleonTemplate $template
+ * @param \DOMElement|null $domElement
+ * @param int $indent
+ */
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+
+ parent::__construct( $template, $domElement, $indent );
+
+ // add classes for the normal case where the page tools are displayed as a first class element;
+ // these classes should be removed if the page tools are part of another element, e.g. nav bar
+ $this->addClasses( 'list-inline text-center' );
+ }
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return string the HTML code
+ */
+ public function getHtml() {
+
+ $contentNavigation = $this->getPageToolsStructure();
+
+ if ( $this->hideSelectedNamespace() ) {
+ unset( $contentNavigation[ 'namespaces' ][ $this->getNamespaceKey() ] );
+ }
+
+ $ret = '';
+
+ $this->indent( 2 );
+ foreach ( $contentNavigation as $category => $tabsDescription ) {
+ $ret .= $this->buildTabGroup( $category, $tabsDescription );
+ }
+ $this->indent( -2 );
+
+ 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;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function &getPageToolsStructure() {
+ if ( $this->mPageToolsStructure === null ) {
+ $this->mPageToolsStructure = $this->getSkinTemplate()->get( 'content_navigation' , null );
+ }
+ return $this->mPageToolsStructure;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function hideSelectedNamespace() {
+ return
+ $this->getDomElement() !== null &&
+ filter_var( $this->getDomElement()->getAttribute( 'hideSelectedNameSpace' ), FILTER_VALIDATE_BOOLEAN ) &&
+ Action::getActionName( $this->getSkin() ) === 'view';
+ }
+
+ /**
+ * 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 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;
+ }
+
+ /**
+ * @param string $category
+ * @param mixed[][] $tabsDescription
+ *
+ * @return string
+ */
+ protected function buildTabGroup( $category, $tabsDescription ) {
+ // TODO: visually group all links of one category (e.g. some space between categories)
+
+ if ( empty( $tabsDescription ) ) {
+ return '';
+ }
+
+ $ret = $this->indent() . '<!-- ' . $category . ' -->';
+
+ if ( !$this->mFlat ) {
+ $ret .= $this->buildTabGroupOpeningTags( $category );
+
+ }
+
+ foreach ( $tabsDescription as $key => $tabDescription ) {
+ $ret .= $this->buildTab( $tabDescription, $key );
+ }
+
+ if ( !$this->mFlat ) {
+ $ret .= $this->buildTabGroupClosingTags();
+ }
+ return $ret;
+ }
+
+ /**
+ * @param string $category
+ *
+ * @return string
+ */
+ protected function buildTabGroupOpeningTags( $category ) {
+ // output the name of the current category (e.g. 'namespaces', 'views', ...)
+ $ret = $this->indent() .
+ \Html::openElement( 'li', array( 'id' => IdRegistry::getRegistry()->getId( 'p-' . $category ) ) ) .
+ $this->indent( 1 ) . '<ul class="list-inline" >';
+
+ $this->indent( 1 );
+ return $ret;
+ }
+
+ /**
+ * @param mixed[] $tabDescription
+ * @param string $key
+ *
+ * @return string
+ */
+ protected function buildTab( $tabDescription, $key ) {
+
+ // skip redundant links (i.e. the 'view' link)
+ // TODO: make this dependent on an option
+ if ( array_key_exists( 'redundant', $tabDescription ) && $tabDescription[ 'redundant' ] === true ) {
+ return '';
+ }
+
+ // apply a link class if specified, e.g. for the currently active namespace
+ $options = array();
+ if ( array_key_exists( 'class', $tabDescription ) ) {
+ $options[ 'link-class' ] = $tabDescription[ 'class' ];
+ }
+
+ return $this->indent() . $this->getSkinTemplate()->makeListItem( $key, $tabDescription, $options );
+
+ }
+
+ /**
+ * @return string
+ */
+ protected function buildTabGroupClosingTags() {
+ return $this->indent( -1 ) . '</ul>' .
+ $this->indent( -1 ) . '</li>';
+ }
+
+ /**
+ * Set the page tool menu to have submenus or not
+ *
+ * @param boolean $flat
+ */
+ public function setFlat( $flat ) {
+ $this->mFlat = $flat;
+ }
+
+ /**
+ * Set the page tool menu to have submenus or not
+ *
+ * @param string|string[] $tools
+ */
+ public function setRedundant( $tools ) {
+ if ( is_string( $tools ) ) {
+ $tools = array( $tools );
+ }
+
+ $pageToolsStructure = &$this->getPageToolsStructure();
+
+ foreach ( $tools as $tool ) {
+ foreach ( $pageToolsStructure as $group => $groupStructure ) {
+ if ( array_key_exists( $tool, $groupStructure ) ) {
+ $pageToolsStructure[ $group ][ $tool ][ 'redundant' ] = true;
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/PersonalTools.php b/www/wiki/skins/chameleon/src/Components/PersonalTools.php
new file mode 100644
index 00000000..fed5a695
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/PersonalTools.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * File holding the PersonalTools class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+/**
+ * The PersonalTools class.
+ *
+ * An unordered list of personal tools: <ul id="p-personal" >...
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class PersonalTools extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $ret = $this->indent() . '<!-- personal tools -->' .
+ $this->indent() . '<div class="p-personal ' . $this->getClassString() . '" id="p-personal" >';
+
+ $ret .= $this->indent( 1 ) . '<ul class="p-personal-tools list-inline pull-right" >';
+
+ $this->indent( 1 );
+
+ // add personal tools (links to user page, user talk, prefs, ...)
+ foreach ( $this->getSkinTemplate()->getPersonalTools() as $key => $item ) {
+ $ret .= $this->indent() . $this->getSkinTemplate()->makeListItem( $key, $item );
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' .
+ $this->indent( -1 ) . '</div>' . "\n" .
+ $this->getNewtalkNotifier();
+
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ private function getNewtalkNotifier() {
+
+ if ( $this->getDomElement() !== null && filter_var( $this->getDomElement()->getAttribute( 'hideNewtalkNotifier' ), FILTER_VALIDATE_BOOLEAN ) ) {
+ return '';
+ }
+
+ // include message to a user about new messages on their talkpage
+ $newtalkNotifier = new NewtalkNotifier( $this->getSkinTemplate(), null, $this->getIndent() + 2 );
+
+ return $this->indent() . '<div class="newtalk-notifier pull-right">' . $newtalkNotifier->getHtml() .
+ $this->indent() . '</div>';
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Row.php b/www/wiki/skins/chameleon/src/Components/Row.php
new file mode 100644
index 00000000..70675934
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Row.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * File holding the Row class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Skins\Chameleon\ChameleonTemplate;
+
+/**
+ * The Row class.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Row extends Container {
+
+ public function __construct( ChameleonTemplate $template, \DOMElement $domElement = null, $indent = 0 ) {
+
+ parent::__construct( $template, $domElement, $indent );
+ $this->addClasses( 'row' );
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/SearchBar.php b/www/wiki/skins/chameleon/src/Components/SearchBar.php
new file mode 100644
index 00000000..89937975
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/SearchBar.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * File holding the SearchBar class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 SearchBar class.
+ *
+ * The search form wrapped in a div: <div id="p-search" role="search" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class SearchBar extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return string
+ */
+ public function getHtml() {
+
+ $ret = $this->indent() . '<!-- search form -->' .
+
+ $this->indent() . '<div ' . \Html::expandAttributes( array(
+ 'id' => IdRegistry::getRegistry()->getId( 'p-search' ),
+ 'class' => 'p-search ' . $this->getClassString(),
+ 'role' => 'search',
+ )
+ ) . Linker::tooltip( 'p-search' ) . '>' .
+
+ $this->indent( 1 ) . '<form ' . \Html::expandAttributes( array(
+ 'id' => IdRegistry::getRegistry()->getId( 'searchform' ),
+ 'class' => 'mw-search form-inline',
+ )
+ ) . ' action="' . $this->getSkinTemplate()->data[ 'wgScript' ] . '">' .
+
+ $this->indent( 1 ) . '<input type="hidden" name="title" value="' . $this->getSkinTemplate()->data[ 'searchtitle' ] . '" />' .
+ $this->indent() . '<div class="input-group">' .
+ $this->indent( 1 ) . $this->getSkinTemplate()->makeSearchInput( array( 'id' => IdRegistry::getRegistry()->getId( 'searchInput' ), 'type' => 'text', 'class' => 'form-control' ) ) .
+ $this->indent() . '<div class="input-group-btn">';
+
+ $this->indent( 1 );
+
+ $ret .=
+ $this->getGoButton() .
+ $this->getSearchButton() .
+ $this->indent( -1 ) . '</div>' .
+ $this->indent( -1 ) . '</div>' .
+ $this->indent( -1 ) . '</form>' .
+ $this->indent( -1 ) . '</div>' . "\n";
+
+ return $ret;
+ }
+
+ /**
+ * @return string
+ */
+ private function getGoButton() {
+
+ $valueAttr = 'searcharticle';
+ $idAttr = 'searchGoButton';
+ $nameAttr = 'go';
+ $glyphicon = ( $this->getAttribute( 'buttons' ) === 'go' ? 'search' : 'share-alt' );
+
+ return $this->getButton( 'go', $valueAttr, $idAttr, $nameAttr, $glyphicon );
+ }
+
+ /**
+ * @return string
+ */
+ private function getSearchButton() {
+
+ $valueAttr = 'searchbutton';
+ $idAttr = 'mw-searchButton';
+ $nameAttr = 'fulltext';
+ $glyphicon = 'search';
+
+ return $this->getButton( 'search', $valueAttr, $idAttr, $nameAttr, $glyphicon );
+ }
+
+ /**
+ * @param $valueAttr
+ * @param $idAttr
+ * @param $nameAttr
+ * @param $glyphicon
+ * @return string
+ */
+ private function getButton( $button, $valueAttr, $idAttr, $nameAttr, $glyphicon ) {
+
+ if ( $this->shouldShowButton( $button ) ) {
+
+ $buttonAttrs = array(
+ 'value' => $this->getSkinTemplate()->getSkin()->msg( $valueAttr ),
+ 'id' => IdRegistry::getRegistry()->getId( $idAttr ),
+ 'name' => $nameAttr,
+ 'type' => 'submit',
+ 'class' => $idAttr . ' btn btn-default'
+ );
+
+ $buttonAttrs = array_merge(
+ $buttonAttrs,
+ Linker::tooltipAndAccesskeyAttribs( "search-$nameAttr" )
+ );
+
+ return $this->indent() . \Html::rawElement( 'button', $buttonAttrs, '<span class="glyphicon glyphicon-' . $glyphicon . '"></span>' );
+ }
+
+ return '';
+ }
+
+ private function shouldShowButton( $button ) {
+ $buttonsAttribute = $this->getAttribute( 'buttons' );
+ return $button === 'go' && $buttonsAttribute !== 'search' ||
+ $button === 'search' && $buttonsAttribute !== 'go';
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Silent.php b/www/wiki/skins/chameleon/src/Components/Silent.php
new file mode 100644
index 00000000..10726328
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Silent.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * File holding the Silent component class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+
+/**
+ * The Silent class.
+ *
+ * This component may be used as a placeholder during development.
+ *
+ * It is also used internally.
+ *
+ * @author Stephan Gambke
+ * @since 1.1
+ * @ingroup Skins
+ */
+class Silent extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+ return '';
+ }
+}
diff --git a/www/wiki/skins/chameleon/src/Components/SiteNotice.php b/www/wiki/skins/chameleon/src/Components/SiteNotice.php
new file mode 100644
index 00000000..1b1b53e6
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/SiteNotice.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * File holding the SiteNotice class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2014, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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;
+
+/**
+ * The SiteNotice class.
+ *
+ * A simple div containing the site notice text: <div id="siteNotice" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class SiteNotice extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $data = $this->getSkinTemplate()->data;
+
+ if ( array_key_exists( 'sitenotice', $data ) && $data[ 'sitenotice' ] ) {
+
+ return $this->indent() . '<!-- sitenotice -->' .
+ $this->indent() . '<div id="siteNotice" class="siteNotice ' . $this->getClassString() . '" >' . $data[ 'sitenotice' ] . '</div>'
+ . "\n";
+ } else {
+ return "\n";
+ }
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/Structure.php b/www/wiki/skins/chameleon/src/Components/Structure.php
new file mode 100644
index 00000000..dee8a39e
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/Structure.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * File holding the Structure class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2017, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 DOMElement;
+
+/**
+ * The Structure class.
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class Structure extends Component {
+
+ private $subcomponents;
+
+ /**
+ * Builds the HTML code for the component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml(){
+ $ret = '';
+
+ foreach ( $this->getSubcomponents() as $component ) {
+ $ret .= $component->getHtml();
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @return string[] the resource loader modules needed by this component
+ */
+ public function getResourceLoaderModules() {
+ $modules = array();
+
+ foreach ( $this->getSubcomponents() as $component ) {
+ $modules = array_merge( $modules, $component->getResourceLoaderModules() );
+ }
+
+ return $modules;
+ }
+
+ /**
+ * @return Component[]
+ */
+ protected function getSubcomponents() {
+
+ if ( !isset ( $this->subcomponents ) ) {
+
+ $this->subcomponents = array();
+
+ $domElement = $this->getDomElement();
+
+ if ( $domElement !== null && $domElement instanceof DOMElement ) {
+
+ $children = $this->getDomElement()->childNodes;
+
+ foreach ( $children as $child ) {
+ if ( $child instanceof DOMElement ) {
+ $this->subcomponents[] = $this->getSkin()->getComponentFactory()->getComponent( $child, $this->getIndent() + 1 );
+ }
+ }
+
+ }
+ }
+
+ return $this->subcomponents;
+ }
+
+}
diff --git a/www/wiki/skins/chameleon/src/Components/ToolbarHorizontal.php b/www/wiki/skins/chameleon/src/Components/ToolbarHorizontal.php
new file mode 100644
index 00000000..255cec14
--- /dev/null
+++ b/www/wiki/skins/chameleon/src/Components/ToolbarHorizontal.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * File containing the ToolbarHorizontal class
+ *
+ * This file is part of the MediaWiki skin Chameleon.
+ *
+ * @copyright 2013 - 2016, Stephan Gambke
+ * @license GNU General Public License, version 3 (or any later version)
+ *
+ * The Chameleon skin 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 skin 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 Hooks;
+use Linker;
+
+/**
+ * ToolbarHorizontal class
+ *
+ * A horizontal toolbar containing standard sidebar items (toolbox, language links).
+ *
+ * The toolbar is an unordered list in a nav element: <nav role="navigation" id="p-tb" >
+ *
+ * @author Stephan Gambke
+ * @since 1.0
+ * @ingroup Skins
+ */
+class ToolbarHorizontal extends Component {
+
+ /**
+ * Builds the HTML code for this component
+ *
+ * @return String the HTML code
+ */
+ public function getHtml() {
+
+ $skinTemplate = $this->getSkinTemplate();
+
+ $ret = $this->indent() . '<!-- ' . htmlspecialchars( $skinTemplate->getMsg( 'toolbox' )->text() ) . '-->' .
+ $this->indent() . '<nav class="navbar navbar-default p-tb ' . $this->getClassString() . '" id="p-tb" ' . Linker::tooltip( 'p-tb' ) . ' >' .
+ $this->indent( 1 ) . '<ul class="nav navbar-nav small">';
+
+ $this->indent( 1 );
+
+ // insert toolbox items
+ if ( !$this->hideTools() ) {
+ $ret .= $this->addTools( $skinTemplate );
+ }
+
+ // insert language links
+ if ( !$this->hideLanguages() ) {
+ $ret .= $this->addLanguageLinks( $skinTemplate );
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' .
+ $this->indent( -1 ) . '</nav>' . "\n";
+
+ return $ret;
+ }
+
+ /**
+ * @param $skinTemplate
+ * @return string
+ * @throws \FatalError
+ * @throws \MWException
+ */
+ private function addTools( $skinTemplate ) {
+
+ $ret = '';
+
+ // TODO: Do we need to care of dropdown menus here? E.g. RSS feeds? See SkinTemplateToolboxEnd.php:1485
+ foreach ( $skinTemplate->getToolbox() as $key => $tbitem ) {
+ $ret .= $this->indent() . $skinTemplate->makeListItem( $key, $tbitem );
+ }
+
+ ob_start();
+ // We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
+ // can abort and avoid outputting double toolbox links
+ Hooks::run( 'SkinTemplateToolboxEnd', array( &$skinTemplate, true ) );
+ $ret .= $this->indent() . ob_get_contents();
+ ob_end_clean();
+ return $ret;
+ }
+
+ /**
+ * @param $skinTemplate
+ * @return string
+ * @throws \MWException
+ */
+ private function addLanguageLinks( $skinTemplate ) {
+
+ $ret = '';
+
+ if ( array_key_exists( 'language_urls', $skinTemplate->data ) && $skinTemplate->data[ 'language_urls' ] ) {
+
+ $ret .= $this->indent() . '<li class="dropdown dropup p-lang" id="p-lang" ' . Linker::tooltip( 'p-lang' ) . ' >' .
+ $this->indent( 1 ) . '<a href="#" data-target="#" class="dropdown-toggle" data-toggle="dropdown">' .
+ htmlspecialchars( $skinTemplate->getMsg( 'otherlanguages' )->text() ) . ' <b class="caret"></b>' . '</a>' .
+ $this->indent() . '<ul class="dropdown-menu" >';
+
+ $this->indent( 1 );
+ foreach ( $skinTemplate->data[ 'language_urls' ] as $key => $langlink ) {
+ $ret .= $this->indent() . $skinTemplate->makeListItem( $key, $langlink, array( 'link-class' => 'small' ) );
+ }
+
+ $ret .= $this->indent( -1 ) . '</ul>' .
+ $this->indent( -1 ) . '</li>';
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @return bool
+ */
+ private function hideTools() {
+ return $this->getDomElement() !== null && filter_var( $this->getDomElement()->getAttribute( 'hideTools' ), FILTER_VALIDATE_BOOLEAN );
+ }
+
+ /**
+ * @return bool
+ */
+ private function hideLanguages() {
+ return $this->getDomElement() !== null && filter_var( $this->getDomElement()->getAttribute( 'hideLanguages' ), FILTER_VALIDATE_BOOLEAN );
+ }
+
+}