diff options
author | Yaco <franco@reevo.org> | 2020-06-04 11:01:00 -0300 |
---|---|---|
committer | Yaco <franco@reevo.org> | 2020-06-04 11:01:00 -0300 |
commit | fc7369835258467bf97eb64f184b93691f9a9fd5 (patch) | |
tree | daabd60089d2dd76d9f5fb416b005fbe159c799d /www/wiki/skins/chameleon/src/Menu |
first commit
Diffstat (limited to 'www/wiki/skins/chameleon/src/Menu')
-rw-r--r-- | www/wiki/skins/chameleon/src/Menu/Menu.php | 118 | ||||
-rw-r--r-- | www/wiki/skins/chameleon/src/Menu/MenuFactory.php | 91 | ||||
-rw-r--r-- | www/wiki/skins/chameleon/src/Menu/MenuFromLines.php | 273 |
3 files changed, 482 insertions, 0 deletions
diff --git a/www/wiki/skins/chameleon/src/Menu/Menu.php b/www/wiki/skins/chameleon/src/Menu/Menu.php new file mode 100644 index 00000000..78ae3f76 --- /dev/null +++ b/www/wiki/skins/chameleon/src/Menu/Menu.php @@ -0,0 +1,118 @@ +<?php +/** + * File holding the abstract Menu 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\Menu; + +/** + * Class Menu + * + * @author Stephan Gambke + * @since 1.0 + * @ingroup Skins + */ +abstract class Menu { + + private $menuItemFormatter = null; + private $itemListFormatter = null; + + abstract public function getHtml(); + + /** + * @param string $href + * @param string $text + * @param int $depth + * @param string $subitems + * + * @return string + */ + protected function getHtmlForMenuItem( $href, $text, $depth, $subitems ) { + return call_user_func( $this->getMenuItemFormatter(), $href, $text, $depth, $subitems ); + } + + /** + * @return callable + */ + public function getMenuItemFormatter() { + + if ( $this->menuItemFormatter === null ) { + + $this->setMenuItemFormatter( function ( $href, $text, $depth, $subitems ) { + $href = \Sanitizer::cleanUrl( $href ); + $text = htmlspecialchars( $text ); + $indent = str_repeat( "\t", 2 * $depth ); + + if ( $subitems !== '' ) { + return "$indent<li>\n$indent\t<a href=\"$href\">$text</a>\n$subitems$indent</li>\n"; + } else { + return "$indent<li><a href=\"$href\">$text</a></li>\n"; + } + } ); + + } + + return $this->menuItemFormatter; + } + + /** + * @param callable $menuItemFormatter + */ + public function setMenuItemFormatter( $menuItemFormatter ) { + $this->menuItemFormatter = $menuItemFormatter; + } + + /** + * @param string $rawItemsHtml + * @param int $depth + * + * @return string + */ + protected function getHtmlForMenuItemList( $rawItemsHtml, $depth ) { + return call_user_func( $this->getItemListFormatter(), $rawItemsHtml, $depth ); + } + + /** + * @return callable + */ + public function getItemListFormatter() { + + if ( $this->itemListFormatter === null ) { + $this->setItemListFormatter( function ( $rawItemsHtml, $depth ) { + $indent = str_repeat( "\t", 2 * $depth + 1 ); + return "$indent<ul>\n$rawItemsHtml$indent</ul>\n"; + } ); + } + + return $this->itemListFormatter; + } + + /** + * @param callable $itemListFormatter + */ + public function setItemListFormatter( $itemListFormatter ) { + $this->itemListFormatter = $itemListFormatter; + } + +} diff --git a/www/wiki/skins/chameleon/src/Menu/MenuFactory.php b/www/wiki/skins/chameleon/src/Menu/MenuFactory.php new file mode 100644 index 00000000..b1f71779 --- /dev/null +++ b/www/wiki/skins/chameleon/src/Menu/MenuFactory.php @@ -0,0 +1,91 @@ +<?php +/** + * File holding the MenuFactory 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\Menu; +use Message; + +/** + * Class MenuFactory + * + * @author Stephan Gambke + * @since 1.0 + * @ingroup Skins + */ +class MenuFactory { + + /** + * @param Message|string|string[] $message + * @param bool $forContent + * + * @throws \MWException + * + * @return Menu + */ + public function getMenuFromMessage( $message, $forContent = false ) { + + if ( is_string( $message ) || is_array( $message ) ) { + $message = Message::newFromKey( $message ); + } + + $this->assert( $message instanceof Message, 'String, array of strings or Message object expected.', $message ); + + if ( $forContent ) { + $message = $message->inContentLanguage(); + } + + if ( !$message->exists() ) { + return $this->getMenuFromMessageText( '', $forContent ); + } + + return $this->getMenuFromMessageText( $message->text(), $forContent ); + } + + /** + * @param string $text + * @param bool $forContent + * + * @return Menu + * @throws \MWException + */ + public function getMenuFromMessageText( $text, $forContent = false ) { + + $this->assert( is_string( $text ), 'String expected.', $text ); + + $lines = explode( "\n", trim( $text ) ); + + return new MenuFromLines( $lines, $forContent ); + } + + /** + * @param $message + * @throws \MWException + */ + protected function assert( $condition, $message, $target ) { + if ( !$condition ) { + throw new \MWException( $message . ' Got ' . (is_object( $target ) ? get_class( $target ) : gettype( $target )) . '.' ); + } + } +} diff --git a/www/wiki/skins/chameleon/src/Menu/MenuFromLines.php b/www/wiki/skins/chameleon/src/Menu/MenuFromLines.php new file mode 100644 index 00000000..ea55fabc --- /dev/null +++ b/www/wiki/skins/chameleon/src/Menu/MenuFromLines.php @@ -0,0 +1,273 @@ +<?php +/** + * File holding the MenuFromLines class + * + * This file is part of the MediaWiki skin Chameleon. + * + * @copyright 2013 - 2015, 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\Menu; + +use Title; + +/** + * Class MenuFromLines + * + * @author Stephan Gambke + * @since 1.0 + * @ingroup Skins + */ +class MenuFromLines extends Menu { + + private $lines = null; + private $inContentLanguage = false; + private $menuItemData = null; + + private $needsParse = true; + + /** @var Menu[] */ + private $children = array(); + private $html = null; + + /** + * @param string[] $lines + * @param bool $inContentLanguage + * @param null|string[] $itemData + */ + public function __construct( &$lines, $inContentLanguage = false, $itemData = null ) { + + $this->lines = &$lines; + $this->inContentLanguage = $inContentLanguage; + + if ( $itemData !== null ) { + $this->menuItemData = $itemData; + } else { + $this->menuItemData = array( + 'text' => '', + 'href' => '#', + 'depth' => 0 + ); + } + } + + /** + * @return string + */ + public function getHtml() { + + if ( $this->html === null ) { + + $this->parseLines(); + $this->html = $this->buildHtml(); + + } + + return $this->html; + } + + /** + * @return string[]|null + */ + public function parseLines() { + + if ( !$this->needsParse ) { + return null; + } + + $this->needsParse = false; + + $line = $this->getNextLine(); + $subItemData = $this->parseOneLine( $line ); + + while ( $subItemData !== null && $subItemData[ 'depth' ] > $this->menuItemData[ 'depth' ] ) { + + $subItemData = $this->createChildAndParseNextLine( $subItemData ); + + } + + return $subItemData; + } + + /** + * @return string + */ + protected function getNextLine() { + $line = ''; + + while ( count( $this->lines ) > 0 && empty( $line ) ) { + $line = trim( array_shift( $this->lines ) ); + }; + return $line; + } + + /** + * Will return an array of the form + * array( + * 'text' => $text, // link text + * 'href' => $href, // parsed link target + * 'depth' => $depth + * ); + * + * @param string $rawLine + * + * @return array + */ + protected function parseOneLine( $rawLine ) { + + if ( empty( $rawLine ) ) { + return null; + } + + list( $depth, $linkDescription ) = $this->extractDepthAndLine( $rawLine ); + list( $href, $text ) = $this->extractHrefAndLinkText( $linkDescription ); + + return array( + 'text' => $text, + 'href' => $href, + 'depth' => $depth + ); + } + + /** + * @param string $rawLine + * + * @return array + */ + protected function extractDepthAndLine( $rawLine ) { + + $matches = array(); + preg_match( '/(\**)(.*)/', ltrim( $rawLine ), $matches ); + + $depth = strlen( $matches[ 1 ] ); + $line = $matches[ 2 ]; + + return array( $depth, $line ); + } + + /** + * @param $linkDescription + * + * @return array + */ + protected function extractHrefAndLinkText( $linkDescription ) { + + $linkAttributes = array_map( 'trim', explode( '|', $linkDescription, 2 ) ); + + $linkTarget = trim( trim( $linkAttributes[ 0 ], '[]' ) ); + $linkTarget = $this->getTextFromMessageName( $linkTarget ); + $href = $this->getHrefForTarget( $linkTarget ); + + $linkDescription = count( $linkAttributes ) > 1 ? $linkAttributes[ 1 ] : ''; + $text = $linkDescription === '' ? $linkTarget : $this->getTextFromMessageName( $linkDescription ); + + return array( $href, $text ); + } + + /** + * @param string $messageName + * + * @return string + */ + protected function getTextFromMessageName( $messageName ) { + $msgObj = $this->inContentLanguage ? wfMessage( $messageName )->inContentLanguage() : wfMessage( $messageName ); + $messageText = ( $msgObj->isDisabled() ? $messageName : trim( $msgObj->inContentLanguage()->text() ) ); + return $messageText; + } + + /** + * @param string $linkTarget + * + * @return string + * @throws \MWException + */ + protected function getHrefForTarget( $linkTarget ) { + + if ( empty( $linkTarget ) ) { + return '#'; + } elseif ( preg_match( '/^(?:' . wfUrlProtocols() . ')/', $linkTarget ) || $linkTarget[ 0 ] === '#' ) { + return $linkTarget; + } else { + return $this->getHrefForWikiPage( $linkTarget ); + } + } + + /** + * @param string $linkTarget + * + * @return string + * @throws \MWException + */ + protected function getHrefForWikiPage( $linkTarget ) { + $title = Title::newFromText( $linkTarget ); + + if ( $title instanceof Title ) { + return $title->fixSpecialName()->getLocalURL(); + } + + return '#'; + } + + /** + * @param string[] $subItemData + * + * @return null|string[] + */ + protected function createChildAndParseNextLine( $subItemData ) { + $child = new self( $this->lines, $this->inContentLanguage, $subItemData ); + $child->setMenuItemFormatter( $this->getMenuItemFormatter() ); + $child->setItemListFormatter( $this->getItemListFormatter() ); + $subItemData = $child->parseLines(); + $this->children[ ] = $child; + return $subItemData; + } + + /** + * @return string + */ + protected function buildHtml() { + + $submenuHtml = $this->buildSubmenuHtml(); + + if ( $this->menuItemData[ 'text' ] !== '' ) { + return $this->getHtmlForMenuItem( $this->menuItemData[ 'href' ], $this->menuItemData[ 'text' ], $this->menuItemData[ 'depth' ], $submenuHtml ); + } else { + return $submenuHtml; + } + } + + /** + * @return string + */ + protected function buildSubmenuHtml() { + + if ( empty( $this->children ) ) { + return ''; + } + + $itemList = ''; + foreach ( $this->children as $child ) { + $itemList .= $child->getHtml(); + } + + return $this->getHtmlForMenuItemList( $itemList, $this->menuItemData[ 'depth' ] ); + } + +} |