Netbrain has submitted this change and it was merged.

Change subject: Added #subpage functionality and various minor fixes * improved 
error reporting on syntax failure * fixed small js scope issue
......................................................................


Added #subpage functionality and various minor fixes
* improved error reporting on syntax failure
* fixed small js scope issue

Given the subpages A/B/C

<sidebarmenu>
 #subpage A
</sidebarmenu>

would render a sidebarmenu with the same hierarchical structure
as the subpages equivalent to the input:

<sidebarmenu>
A
*B
**C
<sidebarmenu>

Subpages can also be included anywhere in the tree structure
E.g

<sidebarmenu>
My subpages a couple of levels down
* A tree of subpages is closing...
** A tree of subpages is IMINENT!
*** #subpage A
</sidebarmenu>

Additionally subpages can be prefixed with -/+ indicating wether
the entire tree and the children should be collapsed or expanded

Change-Id: Ifaf87db3bd0a86aa871022d7c906050e95269720
---
M SideBarMenu.i18n.php
M js/ext.sidebarmenu.js
M src/Hooks.php
A src/SubPage/SubPageRenderer.php
4 files changed, 222 insertions(+), 82 deletions(-)

Approvals:
  Netbrain: Verified; Looks good to me, approved



diff --git a/SideBarMenu.i18n.php b/SideBarMenu.i18n.php
index 70ef266..f4752ad 100644
--- a/SideBarMenu.i18n.php
+++ b/SideBarMenu.i18n.php
@@ -36,6 +36,7 @@
        'sidebarmenu-edit' => 'Action link. The text of the link which points 
to the edit page wherever the sidebarmenu is declared.',
        'sidebarmenu-parser-menuitem-expanded-null' => 'The value of the 
expanded property of a menuitem',
        'sidebarmenu-parser-config-error' => 'Config parameters passed to the 
extension is incorrect (wrong parameter key or value)',
+       'sidebarmenu-parser-subpage-error' => 'Error message presented when 
illegal or incorrect value for #subpage title',
        'sidebarmenu-param-expanded' => 'Parameter which causes all menu items 
to be expanded by default unless explicit set',
        'sidebarmenu-param-show' => 'Parameter which sets the show text that is 
visible when a menu item is hidden',
        'sidebarmenu-param-hide' => 'Parameter which sets the hide text that is 
visible when a menu item is shown',
diff --git a/js/ext.sidebarmenu.js b/js/ext.sidebarmenu.js
index c604cba..f52a97b 100644
--- a/js/ext.sidebarmenu.js
+++ b/js/ext.sidebarmenu.js
@@ -16,67 +16,70 @@
             for (var id in sidebarmenu){
                 var container = $('#'+id);
                 var config = sidebarmenu[id];
-                var showText = config[SBM_CONTROLS_SHOW];
-                var hideText = config[SBM_CONTROLS_HIDE];
-                var useAnimations = config[SBM_JS_ANIMATE];
-                var minimized = config[SBM_MINIMIZED];
 
-                if(minimized){
-                    container.addClass('sidebar-menu-minimized');
-                    container.find('.sidebar-menu-0 
.sidebar-menu-item').first()
-                        .removeClass('sidebar-menu-item-expanded')
-                        .addClass('sidebar-menu-item-collapsed');
-                }
+                (function(container,config){
 
-                function initControls() {
-                    
container.find('.sidebar-menu-item-collapsed').children('.sidebar-menu-item-text-container').children('.sidebar-menu-item-controls').append(showText);
-                    
container.find('.sidebar-menu-item-expanded').children('.sidebar-menu-item-text-container').children('.sidebar-menu-item-controls').append(hideText);
-                }
+                    var showText = config[SBM_CONTROLS_SHOW];
+                    var hideText = config[SBM_CONTROLS_HIDE];
+                    var useAnimations = config[SBM_JS_ANIMATE];
+                    var minimized = config[SBM_MINIMIZED];
 
-                /*Open submenu of current page if current page is present as a 
link in sidebarmenu*/
-                var selfLink = 
container.find('.sidebar-menu-item').find('.selflink')[0]
-                if(selfLink !== undefined ){
-                    
$(selfLink).parents('.sidebar-menu-item-collapsed').removeClass('sidebar-menu-item-collapsed').addClass('sidebar-menu-item-expanded');
-                }
-
-                //initialize controls
-                initControls();
-
-                //initialize click actions
-                
container.find('.sidebar-menu-item-controls,.sidebar-menu-item-expand-action').click(function
 () {
-                    if(minimized && $(this)[0] == 
$('.sidebar-menu-item-controls:first')[0]){
-                        container.toggleClass('sidebar-menu-minimized');
+                    if(minimized){
+                        container.addClass('sidebar-menu-minimized');
+                        container.find('.sidebar-menu-0 
.sidebar-menu-item').first()
+                            .removeClass('sidebar-menu-item-expanded')
+                            .addClass('sidebar-menu-item-collapsed');
                     }
 
-                    var controls = $(this).is('.sidebar-menu-item-controls') ? 
$(this) : $(this).next();
-                    var currentText = controls.text();
-
-                    if (currentText == showText) {
-                        controls.text(hideText);
-                    } else if (currentText == hideText) {
-                        controls.text(showText);
+                    function initControls() {
+                        
container.find('.sidebar-menu-item-collapsed').children('.sidebar-menu-item-text-container').children('.sidebar-menu-item-controls').append(showText);
+                        
container.find('.sidebar-menu-item-expanded').children('.sidebar-menu-item-text-container').children('.sidebar-menu-item-controls').append(hideText);
                     }
 
-                    if (useAnimations) {
-                        //A little "ugly" hack to prevent some gui glitches.
-                        
$(this).parents('.sidebar-menu-item:first').toggleClass('sidebar-menu-item-collapsed
 sidebar-menu-item-expanded', 250).children('.sidebar-menu').show(0, function 
() {
-                            var _this = $(this);
-                            setTimeout(function () {
-                                _this.css('display', '')
-                            }, 250);
-                        });
-                    } else {
-                        
$(this).parents('.sidebar-menu-item:first').toggleClass('sidebar-menu-item-collapsed
 sidebar-menu-item-expanded');
+                    /*Open submenu of current page if current page is present 
as a link in sidebarmenu*/
+                    var selfLink = 
container.find('.sidebar-menu-item').find('.selflink')[0]
+                    if(selfLink !== undefined ){
+                        
$(selfLink).parents('.sidebar-menu-item-collapsed').removeClass('sidebar-menu-item-collapsed').addClass('sidebar-menu-item-expanded');
                     }
-                });
 
-                //must do this in javascript as serverside solution would 
replace this <a href> link with escaped html characters
-                
container.find('.sidebar-menu-item-expand-action').each(function(){
-                    $(this).html('<a href="#" onclick="return 
false;">'+$(this).html()+'</a>');
-                })
+                    //initialize controls
+                    initControls();
+
+                    //initialize click actions
+                    
container.find('.sidebar-menu-item-controls,.sidebar-menu-item-expand-action').click(function
 () {
+                        if(minimized && $(this)[0] == 
$('.sidebar-menu-item-controls:first')[0]){
+                            container.toggleClass('sidebar-menu-minimized');
+                        }
+
+                        var controls = 
$(this).is('.sidebar-menu-item-controls') ? $(this) : $(this).next();
+                        var currentText = controls.text();
+
+                        if (currentText == showText) {
+                            controls.text(hideText);
+                        } else if (currentText == hideText) {
+                            controls.text(showText);
+                        }
+
+                        if (useAnimations) {
+                            //A little "ugly" hack to prevent some gui 
glitches.
+                            
$(this).parents('.sidebar-menu-item:first').toggleClass('sidebar-menu-item-collapsed
 sidebar-menu-item-expanded', 250).children('.sidebar-menu').show(0, function 
() {
+                                var _this = $(this);
+                                setTimeout(function () {
+                                    _this.css('display', '')
+                                }, 250);
+                            });
+                        } else {
+                            
$(this).parents('.sidebar-menu-item:first').toggleClass('sidebar-menu-item-collapsed
 sidebar-menu-item-expanded');
+                        }
+                    });
+
+                    //must do this in javascript as serverside solution would 
replace this <a href> link with escaped html characters
+                    
container.find('.sidebar-menu-item-expand-action').each(function(){
+                        $(this).html('<a href="#" onclick="return 
false;">'+$(this).html()+'</a>');
+                    })
+                })(container,config);
             }
-
-            container.show();
-            }
+            $('.sidebar-menu-container').show();
+        }
     });
 })($,mw)
diff --git a/src/Hooks.php b/src/Hooks.php
index ddb731d..c2755c6 100644
--- a/src/Hooks.php
+++ b/src/Hooks.php
@@ -2,50 +2,62 @@
 
 namespace SideBarMenu;
 use ParamProcessor\Processor;
+use \SideBarMenu\SubPage\SubPageRenderer;
 
 class Hooks {
 
        public static function init(\Parser &$parser) {
-               $parser->setHook('sidebarmenu', 
'SideBarMenu\Hooks::renderFromTag');
+               $parser->setHook('sidebarmenu', 
'SideBarMenu\Hooks::renderSideBarMenuFromTag');
                return true;
        }
 
-       public static function renderFromTag($input, array $args, \Parser 
$parser, \PPFrame $frame) {
-               $parser->getOutput()->addModules('ext.sidebarmenu.core');
-               $input = $parser->recursiveTagParse($input,$frame);
 
-               //default settings
-               $parameters = self::getTagConfig($args);
-               $config = array();
-               if(count($parameters->getErrors()) > 0){
-                       $errors = 
wfMessage('sidebarmenu-parser-config-error')."\n";
-                       foreach($parameters->getErrors() as $error){
-                               $errors .= '* '.$error->getMessage()."\n";
-                       }
-                       return $errors;
-               }else{
-                       foreach($parameters->getParameters() as $param){
-                               $config[$param->getName()] = $param->getValue();
-                       }
-               }
-
-               $id = uniqid('sidebar-menu-id-');
-               $output = '<div id="'.$id.'" 
class="sidebar-menu-container'.(is_null($config[SBM_CLASS])? '' : ' 
'.$config[SBM_CLASS]).'" style="display:none;'.(is_null($config[SBM_STYLE])? '' 
: $config[SBM_STYLE]).'">';
+       public static function renderSideBarMenuFromTag($input, array $args, 
\Parser $parser, \PPFrame $frame) {
                try {
+                       
$parser->getOutput()->addModules('ext.sidebarmenu.core');
+                       $input = $parser->recursiveTagParse($input,$frame);
+
+                       if(strpos($input,'#subpage ') !== false){
+                               //subpages handling
+                               $parser->disableCache();
+                               SubPageRenderer::renderSubPages($input);
+                               $input = str_replace("\n\n","\n",$input);
+                               $input = 
$parser->recursiveTagParse($input,$frame);
+                       }
+
+                       //default settings
+                       $parameters = self::getTagConfig($args);
+                       $config = array();
+                       if(count($parameters->getErrors()) > 0){
+                               $errors = 
wfMessage('sidebarmenu-parser-config-error')."\n";
+                               foreach($parameters->getErrors() as $error){
+                                       $errors .= '* 
'.$error->getMessage()."\n";
+                               }
+                               return $errors;
+                       }else{
+                               foreach($parameters->getParameters() as $param){
+                                       $config[$param->getName()] = 
$param->getValue();
+                               }
+                       }
+
+                       $id = uniqid('sidebar-menu-id-');
+                       $output = '<div id="'.$id.'" 
class="sidebar-menu-container'.(is_null($config[SBM_CLASS])? '' : ' 
'.$config[SBM_CLASS]).'" style="display:none;'.(is_null($config[SBM_STYLE])? '' 
: $config[SBM_STYLE]).'">';
+
                        $menuParser = new MenuParser($config);
                        $output .= $menuParser->getMenuTree($input)->toHTML();
+
+                       if ($config[SBM_EDIT_LINK]) {
+                               $output .= \Linker::link($frame->getTitle(), 
wfMessage('sidebarmenu-edit')->escaped(), array('title' => 
wfMessage('sidebarmenu-edit')->escaped(), 'class' => 'sidebar-menu-edit-link'), 
array('action' => 'edit'));
+                       }
+                       $output .= '</div>';
+
+                       $jsOutput = self::getJSConfig($config,$id);
+                       return array($jsOutput . $output, 'noparse' => true, 
'isHTML' => true);
+
                } catch (\Exception $x) {
                        wfDebug("An error occured during parsing of: '$input' 
caught exception: $x");
-                       return wfMessage('sidebarmenu-parser-input-error', 
$x->getMessage())->text();
+                       return wfMessage('sidebarmenu-parser-input-error', 
'<strong>'.$x->getMessage()."</strong>\n<pre>$input</pre>")->parse();
                }
-               if ($config[SBM_EDIT_LINK]) {
-                       $output .= \Linker::link($frame->getTitle(), 
wfMessage('sidebarmenu-edit')->escaped(), array('title' => 
wfMessage('sidebarmenu-edit')->escaped(), 'class' => 'sidebar-menu-edit-link'), 
array('action' => 'edit'));
-               }
-               $output .= '</div>';
-
-               $jsOutput = self::getJSConfig($config,$id);
-
-               return array($jsOutput . $output, 'noparse' => true, 'isHTML' 
=> true);
        }
 
        public static function registerUnitTests(&$files) {
diff --git a/src/SubPage/SubPageRenderer.php b/src/SubPage/SubPageRenderer.php
new file mode 100644
index 0000000..d399bbe
--- /dev/null
+++ b/src/SubPage/SubPageRenderer.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * @author: Kim Eik
+ */
+
+namespace SideBarMenu\SubPage;
+
+
+class SubPageRenderer {
+
+       /**
+        * Replaces #subpage occurences with a propertly formatted sidebarmenu 
syntax
+        * of subpages
+        * @param $input
+        */
+       public static function renderSubPages(&$input) {
+               $lines = explode("\n",$input);
+               for($x = 0; $x < count($lines); $x++){
+                       $line = &$lines[$x];
+                       $line = preg_replace_callback("/([-+]*)(\\**)#subpage 
.*/",function($matches){
+                               $title = 
substr($matches[0],strpos($matches[0],'#subpage ')+9);
+                               $title = \Title::newFromText($title);
+                               if(is_null($title)){
+                                       throw new 
\InvalidArgumentException(wfMessage('sidebarmenu-parser-subpage-error'));
+                               }
+                               $subPages = 
SubPageRenderer::getHierarchicalSubpages($title);
+                               $code = 
SubPageRenderer::getSubpagesWikiCode($subPages,$matches[1],strlen($matches[2]));
+                               return $code;
+                       },$line);
+
+               }
+               $input = implode("\n",$lines);
+       }
+
+       /**
+        * Creates wiki code of the subpages that is readable by <sidebarmenu>
+        * @param $subPages
+        * @param string $prefix
+        * @param int $level
+        * @return string
+        */
+       public static function getSubpagesWikiCode($subPages, $prefix = '', 
$level = 0){
+               $result = $prefix;
+               foreach($subPages as $sub => $children){
+                       $sub = \Title::newFromText($sub);
+                       for($i = 0; $i < $level; $i++){
+                               $result .= '*';
+                       }
+                       $result .= 
'[['.$sub->getFullText().'|'.$sub->getSubpageText()."]]\n";
+
+                       if(!empty($children)){
+                               $result .= 
self::getSubpagesWikiCode($children,$prefix,$level+1);
+                       }
+
+               }
+               return $result;
+       }
+
+       /**
+        * Creates a recursively sorted hierarchical representation of subpages
+        * In the form of title->[]children
+        * @param \Title $title
+        * @return array
+        */
+       public static function getHierarchicalSubpages(\Title $title){
+               $titles = array_keys(self::getSubpagesAsSet($title));
+               usort($titles,function($a,$b){
+                       return (substr_count($a,'/') - substr_count($b,'/'));
+               });
+               $relations = array();
+               self::findChildrenOf($title->getFullText(),$titles,$relations);
+               self::tksort($relations);
+               return $relations;
+       }
+
+       public static function findChildrenOf($parentTitle,$titles,&$array){
+               foreach($titles as $childTitle){
+                       if(strpos($childTitle,$parentTitle) === 0){
+                               if(substr_count($parentTitle,'/')+1 === 
substr_count($childTitle,'/')){
+                                       $array[$parentTitle][$childTitle] = 
array();
+                                       
self::findChildrenOf($childTitle,$titles,$array[$parentTitle]);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Retrieves subpages as a set
+        * @param \Title $title
+        * @return array
+        */
+       public static function getSubpagesAsSet(\Title $title, $parent = ''){
+               $subPages = $title->getSubpages();
+               $titles[] = $title;
+               while($subPages->valid()){
+                       $titles[] = $subPages->current();
+                       $subPages->next();
+               }
+
+               $result = array();
+               foreach($titles as $title){
+                       $titleText = $title->getFullText();
+                       $titleTextParts = explode('/',$titleText);
+                       $titleText = '';
+                       foreach($titleTextParts as $part){
+                               $titleText .= $part;
+                               $result[$titleText] = null;
+                               $titleText .= '/';
+                       }
+               }
+               return $result;
+       }
+
+       private static function tksort(&$array){
+               ksort($array);
+               foreach(array_keys($array) as $k)
+               {
+                       if(gettype($array[$k])=="array")
+                       {
+                               self::tksort($array[$k]);
+                       }
+               }
+       }
+}
\ No newline at end of file

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Ifaf87db3bd0a86aa871022d7c906050e95269720
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/SideBarMenu
Gerrit-Branch: master
Gerrit-Owner: Netbrain <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: MathiasLidal <[email protected]>
Gerrit-Reviewer: Netbrain <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to