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