Jack Phoenix has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/108045


Change subject: New class for parsing MediaWiki:Sidebar-like messages into 
modern, nested navigation menus.
......................................................................

New class for parsing MediaWiki:Sidebar-like messages into modern, nested
navigation menus.

This allows to reduce the amount of code duplication needed by custom
skins, as well as ease the porting of WordPress themes into MediaWiki
(many WordPress themes feature a nested navigation menu).

Currently the Nimbus and Monaco skins implement a similar feature, just
without this class.

Based on NavigationService by various Wikia developers.

See https://www.mediawiki.org/wiki/Manual:NestedMenuParser for some more
documentation and an example on how to use this class with a custom skin.

Change-Id: Ib8dc2787f70dc80be6ba9d3c962edc1463247263
---
M RELEASE-NOTES-1.23
M includes/AutoLoader.php
A includes/NestedMenuParser.php
3 files changed, 200 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/45/108045/1

diff --git a/RELEASE-NOTES-1.23 b/RELEASE-NOTES-1.23
index ca8c91b..49d85cf 100644
--- a/RELEASE-NOTES-1.23
+++ b/RELEASE-NOTES-1.23
@@ -75,6 +75,10 @@
 * WikitextContent will now render redirects with the expected "redirect"
   header, rather than as an ordered list. Code calling Article::viewRedirect
   can probably be changed to no longer special-case redirects.
+* Added the NestedMenuParser class to allow skins to turn interface messages
+  formatted similarily to MediaWiki:Sidebar into nested navigation menus.
+  This allows third-party skins to create navigation menus similar to those
+  found on various custom WordPress themes.
 
 === Bug fixes in 1.23 ===
 * (bug 41759) The "updated since last visit" markers (on history pages, recent
diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index bab00f9..79c2ea0 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
@@ -153,6 +153,7 @@
        'MWHttpRequest' => 'includes/HttpFunctions.php',
        'MWInit' => 'includes/Init.php',
        'MWNamespace' => 'includes/Namespace.php',
+       'NestedMenuParser' => 'includes/NestedMenuParser.php',
        'OutputPage' => 'includes/OutputPage.php',
        'Page' => 'includes/WikiPage.php',
        'PageQueryPage' => 'includes/PageQueryPage.php',
diff --git a/includes/NestedMenuParser.php b/includes/NestedMenuParser.php
new file mode 100644
index 0000000..1a0c705
--- /dev/null
+++ b/includes/NestedMenuParser.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * A more advanced parser for parsing messages like MediaWiki:Sidebar into
+ * pretty, modern, nested navigation menus.
+ *
+ * This has been forked from Oasis' NavigationService.
+ * The class name was changed, "magic word" handling was removed from
+ * parseMessage() and some (related) unused functions were also removed.
+ *
+ * @file
+ * @since 1.23
+ * @author Inez KorczyƄski
+ * @see 
https://github.com/Wikia/app/blob/release-136.020/includes/wikia/services/NavigationService.class.php
+ * @see 
https://github.com/Wikia/app/commit/5b132a9dfff4f87c544791295749e44e4b724b92
+ * @see Skin::buildSidebar(), Skin::addToSidebar(), Skin::addToSidebarPlain()
+ */
+class NestedMenuParser {
+
+       /**
+        * Is the message we're supposed to parse in the wiki's content language
+        * (true) or not?
+        * @var bool $forContent
+        */
+       private $forContent = false;
+
+       /**
+        * Internal version number used to create the memcached keys in 
parseMessage()
+        */
+       const version = '0.01';
+
+       /**
+        * Parses a system message by exploding along newlines.
+        *
+        * @param string $messageName Name of the MediaWiki message to parse
+        * @param array $maxChildrenAtLevel
+        * @param int $duration Cache duration for memcached calls
+        * @param bool $forContent Is the message we're supposed to parse in the
+        *                          wiki's content language (true) or not?
+        * @return Array
+        */
+       public function parseMessage( $messageName, $maxChildrenAtLevel = 
array(), $duration, $forContent = false ) {
+               wfProfileIn( __METHOD__ );
+
+               global $wgLang, $wgContLang, $wgMemc;
+
+               $this->forContent = $forContent;
+
+               $useCache = $wgLang->getCode() == $wgContLang->getCode();
+
+               if ( $useCache || $this->forContent ) {
+                       $cacheKey = wfMemcKey( $messageName, self::version );
+                       $nodes = $wgMemc->get( $cacheKey );
+               }
+
+               if ( empty( $nodes ) ) {
+                       if ( $this->forContent ) {
+                               $lines = explode( "\n", wfMessage( $messageName 
)->inContentLanguage()->text() );
+                       } else {
+                               $lines = explode( "\n", wfMessage( $messageName 
)->text() );
+                       }
+                       $nodes = $this->parseLines( $lines, $maxChildrenAtLevel 
);
+
+                       if ( $useCache || $this->forContent ) {
+                               $wgMemc->set( $cacheKey, $nodes, $duration );
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $nodes;
+       }
+
+       /**
+        * Function used by parseMessage() above.
+        *
+        * @param $lines String: newline-separated lines from the supplied MW: 
msg
+        * @param $maxChildrenAtLevel Array:
+        * @return Array
+        */
+       private function parseLines( $lines, $maxChildrenAtLevel = array() ) {
+               wfProfileIn( __METHOD__ );
+
+               $nodes = array();
+
+               if ( is_array( $lines ) && count( $lines ) > 0 ) {
+                       $lastDepth = 0;
+                       $i = 0;
+                       $lastSkip = null;
+
+                       foreach ( $lines as $line ) {
+                               // we are interested only in lines that are not 
empty and start with asterisk
+                               if ( trim( $line ) != '' && $line{0} == '*' ) {
+                                       $depth = strrpos( $line, '*' ) + 1;
+
+                                       if ( $lastSkip !== null && $depth >= 
$lastSkip ) {
+                                               continue;
+                                       } else {
+                                               $lastSkip = null;
+                                       }
+
+                                       if ( $depth == $lastDepth + 1 ) {
+                                               $parentIndex = $i;
+                                       } elseif ( $depth == $lastDepth ) {
+                                               $parentIndex = 
$nodes[$i]['parentIndex'];
+                                       } else {
+                                               for ( $x = $i; $x >= 0; $x-- ) {
+                                                       if ( $x == 0 ) {
+                                                               $parentIndex = 
0;
+                                                               break;
+                                                       }
+                                                       if ( 
$nodes[$x]['depth'] <= $depth - 1 ) {
+                                                               $parentIndex = 
$x;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+
+                                       if ( isset( $maxChildrenAtLevel[$depth 
- 1] ) ) {
+                                               if ( isset( 
$nodes[$parentIndex]['children'] ) ) {
+                                                       if ( count( 
$nodes[$parentIndex]['children'] ) >= $maxChildrenAtLevel[$depth - 1] ) {
+                                                               $lastSkip = 
$depth;
+                                                               continue;
+                                                       }
+                                               }
+                                       }
+
+                                       $node = $this->parseOneLine( $line );
+                                       $node['parentIndex'] = $parentIndex;
+                                       $node['depth'] = $depth;
+
+                                       
$nodes[$node['parentIndex']]['children'][] = $i + 1;
+                                       $nodes[$i + 1] = $node;
+                                       $lastDepth = $node['depth'];
+                                       $i++;
+                               }
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $nodes;
+       }
+
+       /**
+        * @param string $line Line to parse
+        * @return Array containing original, text and href keys (original
+        */
+       private function parseOneLine( $line ) {
+               wfProfileIn( __METHOD__ );
+
+               // trim spaces and asterisks from line and then split it to 
maximum two chunks
+               $lineArr = explode( '|', trim( $line, '* ' ), 2 );
+
+               // trim [ and ] from line to have just http://en.wikipedia.org 
instead of [http://en.wikipedia.org] for external links
+               $lineArr[0] = trim( $lineArr[0], '[]' );
+
+               if ( count( $lineArr ) == 2 && $lineArr[1] != '' ) {
+                       $link = trim( wfMessage( $lineArr[0] 
)->inContentLanguage()->text() );
+                       $desc = trim( $lineArr[1] );
+               } else {
+                       $link = $desc = trim( $lineArr[0] );
+               }
+
+               $text = $this->forContent ? wfMessage( $desc 
)->inContentLanguage() : wfMessage( $desc );
+               if ( $text->isDisabled() ) {
+                       $text = $desc;
+               }
+
+               if ( wfMessage( $lineArr[0] )->isDisabled() ) {
+                       $link = $lineArr[0];
+               }
+
+               if ( preg_match( '/^(?:' . wfUrlProtocols() . ')/', $link ) ) {
+                       $href = $link;
+               } else {
+                       if ( empty( $link ) ) {
+                               $href = '#';
+                       } elseif ( $link{0} == '#' ) {
+                               $href = '#';
+                       } else {
+                               $title = Title::newFromText( $link );
+                               if ( is_object( $title ) ) {
+                                       $href = 
$title->fixSpecialName()->getLocalURL();
+                               } else {
+                                       $href = '#';
+                               }
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+               return array(
+                       'original' => $lineArr[0],
+                       'text' => $text,
+                       'href' => $href
+               );
+       }
+}
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/108045
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib8dc2787f70dc80be6ba9d3c962edc1463247263
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Jack Phoenix <j...@countervandalism.net>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to