summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Williams <andy@andywilliams.me>2017-11-29 11:52:30 +0000
committerAndy Williams <andy@andywilliams.me>2017-11-29 11:52:30 +0000
commite727f07ce51ac56852466f8d2fd66dad8f95a4e3 (patch)
tree9310b8349743408a8d8e394530b13b21885a1534
parent1148adb6bfb9f1f04bf57fe0aa9d27cc4f474a4c (diff)
plugins: Manage our navigation through a plugin not manually
-rw-r--r--public_html/lib/plugins/navi/.travis.yml16
-rw-r--r--public_html/lib/plugins/navi/_test/basicList.test.php97
-rw-r--r--public_html/lib/plugins/navi/_test/externalLinks.test.php76
-rw-r--r--public_html/lib/plugins/navi/_test/general.test.php108
-rw-r--r--public_html/lib/plugins/navi/action.php39
-rw-r--r--public_html/lib/plugins/navi/conf/default.php3
-rw-r--r--public_html/lib/plugins/navi/conf/metadata.php3
-rw-r--r--public_html/lib/plugins/navi/plugin.info.txt8
-rw-r--r--public_html/lib/plugins/navi/script.js12
-rw-r--r--public_html/lib/plugins/navi/style.less45
-rw-r--r--public_html/lib/plugins/navi/syntax.php241
-rw-r--r--public_html/lib/tpl/e/css/modifications.css19
12 files changed, 667 insertions, 0 deletions
diff --git a/public_html/lib/plugins/navi/.travis.yml b/public_html/lib/plugins/navi/.travis.yml
new file mode 100644
index 00000000..f5207aae
--- /dev/null
+++ b/public_html/lib/plugins/navi/.travis.yml
@@ -0,0 +1,16 @@
1# Config file for travis-ci.org
2
3language: php
4php:
5 - "7.0"
6 - "5.6"
7 - "5.5"
8 - "5.4"
9 - "5.3"
10env:
11 matrix:
12 - DOKUWIKI=master
13 - DOKUWIKI=stable
14before_install: wget https://raw.github.com/splitbrain/dokuwiki-travis/master/travis.sh
15install: sh travis.sh
16script: cd _test && phpunit --stderr --group plugin_navi
diff --git a/public_html/lib/plugins/navi/_test/basicList.test.php b/public_html/lib/plugins/navi/_test/basicList.test.php
new file mode 100644
index 00000000..58b8da3b
--- /dev/null
+++ b/public_html/lib/plugins/navi/_test/basicList.test.php
@@ -0,0 +1,97 @@
1<?php
2
3/**
4 * Tests for functionality of the navi plugin
5 *
6 * @group plugin_navi
7 * @group plugins
8 *
9 */
10class basic_plugin_navi_test extends DokuWikiTest {
11
12 protected $pluginsEnabled = array('navi');
13
14 public function setUp() {
15 parent::setUp();
16 }
17
18 public function tearDown() {
19 parent::tearDown();
20 }
21
22 public function test_controlpage_simple() {
23 // arrange
24 $controlpage = " * [[a]]\n * [[b]]\n * [[c]]";
25 saveWikiText('controlpage', $controlpage, '');
26 saveWikiText('navi', '{{navi>controlpage}}', '');
27
28 // act
29 $info = array();
30 $actualHTML = p_render('xhtml', p_get_instructions('{{navi>controlpage}}'), $info);
31
32 // assert
33 $expectedHTML = '<div class="plugin__navi left"><ul>
34<li class="level1 "><div class="li"><a href="/./doku.php?id=a" class="wikilink2" title="a" rel="nofollow">a</a></div>
35</li>
36<li class="level1 close"><div class="li"><a href="/./doku.php?id=b" class="wikilink2" title="b" rel="nofollow">b</a></div>
37</li>
38</ul>
39</div>';
40 $this->assertEquals($expectedHTML, $actualHTML);
41
42 }
43
44 public function test_controlpage_complex() {
45 // arrange
46 $controlpage = "
47 * [[en:products:a:start|BasePage]]
48 * [[en:products:b:d:start|2nd-level Page with hidden child]]
49 * [[en:products:c:projects|hidden 3rd-level page]]
50 * [[en:products:b:archive:start|2nd-level pape]]
51 * [[en:products:c:start|current 2nd-level page with visible child]]
52 * [[en:products:d:start|visible 3rd-level page]]
53";
54 saveWikiText('controlpage', $controlpage, '');
55 saveWikiText('navi', '{{navi>controlpage}}', '');
56 global $ID, $INFO;
57
58 // act
59 $info = array();
60 $ID = 'en:products:c:start';
61 $INFO['id'] = 'en:products:c:start';
62 $actualHTML = p_render('xhtml', p_get_instructions('{{navi>controlpage}}'), $info);
63
64 $pq = phpQuery::newDocumentXHTML($actualHTML);
65
66 $actualPages = array();
67 foreach ($pq->find('a') as $page) {
68 $actualPages[] = $page->getAttribute('title');
69 }
70
71 $actualLiOpen = array();
72 foreach ($pq->find('li.open > div > a, li.open > div > span > a') as $page) {
73 $actualLiOpen[] = $page->getAttribute('title');
74 }
75
76 $actualLiClose = array();
77 foreach ($pq->find('li.close > div > a, li.close > div > span > a') as $page) {
78 $actualLiClose[] = $page->getAttribute('title');
79 }
80
81 $this->assertEquals(array(
82 0 => 'en:products:a:start',
83 1 => 'en:products:b:d:start',
84 2 => 'en:products:b:archive:start',
85 3 => 'en:products:c:start',
86 4 => 'en:products:d:start',
87 ), $actualPages, 'the correct pages in the correct order');
88 $this->assertEquals(array(
89 0 => 'en:products:a:start',
90 1 => 'en:products:c:start',
91 ), $actualLiOpen, 'the pages which have have children and are open should have the "open" class');
92 $this->assertEquals(array(
93 0 => 'en:products:b:d:start',
94 ), $actualLiClose, 'the pages which have have children, but are closed should have the "close" class');
95
96 }
97}
diff --git a/public_html/lib/plugins/navi/_test/externalLinks.test.php b/public_html/lib/plugins/navi/_test/externalLinks.test.php
new file mode 100644
index 00000000..8d54a32e
--- /dev/null
+++ b/public_html/lib/plugins/navi/_test/externalLinks.test.php
@@ -0,0 +1,76 @@
1<?php
2
3/**
4 * Tests for functionality of the navi plugin
5 *
6 * @group plugin_navi
7 * @group plugins
8 *
9 */
10class external_plugin_navi_test extends DokuWikiTest {
11
12 protected $pluginsEnabled = array('navi');
13
14 public function setUp() {
15 parent::setUp();
16 }
17
18 public function tearDown() {
19 parent::tearDown();
20 }
21
22 public function test_controlpage_with_external_link() {
23 // arrange
24 $controlpage = "
25 * [[en:products:a:start|BasePage]]
26 * [[en:products:b:d:start|2nd-level Page with hidden child]]
27 * [[en:products:c:projects|hidden 3rd-level page]]
28 * [[en:products:b:archive:start|2nd-level pape]]
29 * [[en:products:c:start|current 2nd-level page with visible child]]
30 * [[https://www.example.org|Example Page]]
31";
32 saveWikiText('controlpage', $controlpage, '');
33 saveWikiText('navi', '{{navi>controlpage}}', '');
34 global $ID, $INFO;
35
36 // act
37 $info = array();
38 $ID = 'en:products:c:start';
39 $INFO['id'] = 'en:products:c:start';
40 $actualHTML = p_render('xhtml', p_get_instructions('{{navi>controlpage}}'), $info);
41// print_r($actualHTML);
42
43 $pq = phpQuery::newDocumentXHTML($actualHTML);
44
45 $actualPages = array();
46 foreach ($pq->find('a') as $page) {
47 $actualPages[] = $page->getAttribute('title');
48 }
49
50 $actualLiOpen = array();
51 foreach ($pq->find('li.open > div > a, li.open > div > span > a') as $page) {
52 $actualLiOpen[] = $page->getAttribute('title');
53 }
54
55 $actualLiClose = array();
56 foreach ($pq->find('li.close > div > a, li.close > div > span > a') as $page) {
57 $actualLiClose[] = $page->getAttribute('title');
58 }
59
60 $this->assertEquals(array(
61 0 => 'en:products:a:start',
62 1 => 'en:products:b:d:start',
63 2 => 'en:products:b:archive:start',
64 3 => 'en:products:c:start',
65 4 => 'https://www.example.org',
66 ), $actualPages, 'the correct pages in the correct order');
67 $this->assertEquals(array(
68 0 => 'en:products:a:start',
69 1 => 'en:products:c:start',
70 ), $actualLiOpen, 'the pages which have have children and are open should have the "open" class');
71 $this->assertEquals(array(
72 0 => 'en:products:b:d:start',
73 ), $actualLiClose, 'the pages which have have children, but are closed should have the "close" class');
74
75 }
76}
diff --git a/public_html/lib/plugins/navi/_test/general.test.php b/public_html/lib/plugins/navi/_test/general.test.php
new file mode 100644
index 00000000..06eb77b0
--- /dev/null
+++ b/public_html/lib/plugins/navi/_test/general.test.php
@@ -0,0 +1,108 @@
1<?php
2/**
3 * General tests for the navi plugin
4 *
5 * @group plugin_navi
6 * @group plugins
7 */
8class general_plugin_navi_test extends DokuWikiTest {
9
10 /**
11 * Simple test to make sure the plugin.info.txt is in correct format
12 */
13 public function test_plugininfo() {
14 $file = __DIR__.'/../plugin.info.txt';
15 $this->assertFileExists($file);
16
17 $info = confToHash($file);
18
19 $this->assertArrayHasKey('base', $info);
20 $this->assertArrayHasKey('author', $info);
21 $this->assertArrayHasKey('email', $info);
22 $this->assertArrayHasKey('date', $info);
23 $this->assertArrayHasKey('name', $info);
24 $this->assertArrayHasKey('desc', $info);
25 $this->assertArrayHasKey('url', $info);
26
27 $this->assertEquals('navi', $info['base']);
28 $this->assertRegExp('/^https?:\/\//', $info['url']);
29 $this->assertTrue(mail_isvalid($info['email']));
30 $this->assertRegExp('/^\d\d\d\d-\d\d-\d\d$/', $info['date']);
31 $this->assertTrue(false !== strtotime($info['date']));
32 }
33
34 /**
35 * Test to ensure that every conf['...'] entry in conf/default.php has a corresponding meta['...'] entry in
36 * conf/metadata.php.
37 */
38 public function test_plugin_conf() {
39 $conf_file = __DIR__.'/../conf/default.php';
40 if (file_exists($conf_file)){
41 include($conf_file);
42 }
43 $meta_file = __DIR__.'/../conf/metadata.php';
44 if (file_exists($meta_file)) {
45 include($meta_file);
46 }
47
48 $this->assertEquals(gettype($conf), gettype($meta),'Both ' . DOKU_PLUGIN . 'navi/conf/default.php and ' . DOKU_PLUGIN . 'navi/conf/metadata.php have to exist and contain the same keys.');
49
50 if (gettype($conf) != 'NULL' && gettype($meta) != 'NULL') {
51 foreach($conf as $key => $value) {
52 $this->assertArrayHasKey($key, $meta, 'Key $meta[\'' . $key . '\'] missing in ' . DOKU_PLUGIN . 'navi/conf/metadata.php');
53 }
54
55 foreach($meta as $key => $value) {
56 $this->assertArrayHasKey($key, $conf, 'Key $conf[\'' . $key . '\'] missing in ' . DOKU_PLUGIN . 'navi/conf/default.php');
57 }
58 }
59
60 }
61
62
63
64 /*Test that the levels have the right classes
65 public function render_test() {
66 $data = array(
67 0 => '/home/michael/public_html/dokuwiki/data/pages/plugins/navi.txt',
68 1 => array(
69 'lvl1' => array(
70 'parents' => array(),
71 'page' => 'lvl1:start',
72 'title' => '',
73 'lvl' => 1,
74 ),
75 'lvl2' => array(
76 'parents' => Array(
77 0 => 'lvl1',
78 ),
79 'page' => 'lvl2:start',
80 'title' => '',
81 'lvl' => 2,
82 ),
83 'lvl3' => array(
84 'parents' => Array(
85 0 => 'lvl1',
86 1 => 'lvl2',
87 ),
88 'page' => 'lvl3:start',
89 'title' => '',
90 'lvl' => 3,
91 ),
92 'lvl4' => array(
93 'parents' => Array(
94 0 => 'lvl1',
95 1 => 'lvl2',
96 2 => 'lvl3',
97 ),
98 'page' => 'lvl4:start',
99 'title' => '',
100 'lvl' => 4,
101 ),
102
103 ),
104 2 => '',
105 );
106 render('xhtml',$data);
107 }*/
108}
diff --git a/public_html/lib/plugins/navi/action.php b/public_html/lib/plugins/navi/action.php
new file mode 100644
index 00000000..52f133ef
--- /dev/null
+++ b/public_html/lib/plugins/navi/action.php
@@ -0,0 +1,39 @@
1<?php
2/**
3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author Andreas Gohr <gohr@cosmocode.de>
5 */
6if(!defined('DOKU_INC')) die();
7
8if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
9require_once(DOKU_PLUGIN.'action.php');
10
11/**
12 * All DokuWiki plugins to extend the parser/rendering mechanism
13 * need to inherit from this class
14 */
15class action_plugin_navi extends DokuWiki_Action_Plugin {
16
17 /**
18 * plugin should use this method to register its handlers with the dokuwiki's event controller
19 */
20 function register(Doku_Event_Handler $controller) {
21 $controller->register_hook('PARSER_CACHE_USE','BEFORE', $this, 'handle_cache_prepare');
22 }
23
24 /**
25 * prepare the cache object for default _useCache action
26 */
27 function handle_cache_prepare(&$event, $param) {
28 $cache =& $event->data;
29
30 // we're only interested in wiki pages
31 if (!isset($cache->page)) return;
32 if ($cache->mode != 'i') return;
33
34 // get meta data
35 $depends = p_get_metadata($cache->page, 'relation naviplugin');
36 if(!is_array($depends) || !count($depends)) return; // nothing to do
37 $cache->depends['files'] = !empty($cache->depends['files']) ? array_merge($cache->depends['files'], $depends) : $depends;
38 }
39}
diff --git a/public_html/lib/plugins/navi/conf/default.php b/public_html/lib/plugins/navi/conf/default.php
new file mode 100644
index 00000000..3083ff0a
--- /dev/null
+++ b/public_html/lib/plugins/navi/conf/default.php
@@ -0,0 +1,3 @@
1<?php
2
3$conf['arrow'] = 'left';
diff --git a/public_html/lib/plugins/navi/conf/metadata.php b/public_html/lib/plugins/navi/conf/metadata.php
new file mode 100644
index 00000000..a2527be2
--- /dev/null
+++ b/public_html/lib/plugins/navi/conf/metadata.php
@@ -0,0 +1,3 @@
1<?php
2
3$meta['arrow'] = array('multichoice','_choices' => array('left', 'right', 'none'));
diff --git a/public_html/lib/plugins/navi/plugin.info.txt b/public_html/lib/plugins/navi/plugin.info.txt
new file mode 100644
index 00000000..e8ebcfaa
--- /dev/null
+++ b/public_html/lib/plugins/navi/plugin.info.txt
@@ -0,0 +1,8 @@
1base navi
2author Andreas Gohr
3email dokuwiki@cosmocode.de
4date 2016-10-12
5name Navigation Plugin
6desc Build a navigation menu from a list
7url http://www.dokuwiki.org/plugin:navi
8
diff --git a/public_html/lib/plugins/navi/script.js b/public_html/lib/plugins/navi/script.js
new file mode 100644
index 00000000..9658d361
--- /dev/null
+++ b/public_html/lib/plugins/navi/script.js
@@ -0,0 +1,12 @@
1jQuery(function() {
2 'use strict';
3
4 jQuery('li.open, li.close').find('> div.li').each(function (index, element){
5 var link = jQuery(element).find('a').attr('href');
6 var $arrowSpan = jQuery('<span></span>').click(function (event) {
7 window.location = link;
8 });
9 $arrowSpan.addClass('arrowUnderlay');
10 jQuery(element).append($arrowSpan);
11 });
12});
diff --git a/public_html/lib/plugins/navi/style.less b/public_html/lib/plugins/navi/style.less
new file mode 100644
index 00000000..887bf4ba
--- /dev/null
+++ b/public_html/lib/plugins/navi/style.less
@@ -0,0 +1,45 @@
1#dokuwiki__aside, .sidebar_box {
2div.plugin__navi {
3 span.arrowUnderlay {
4 padding: 4px;
5 cursor: pointer;
6 background: no-repeat top right/100%;
7 }
8
9 li.open {
10 span.arrowUnderlay {
11 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAAANlBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3dmhyAAAAEXRSTlMAAQcJCgsUIDZGW2Jjmt75/Rmge4gAAABISURBVBjTY2CgJWDmwBRj4RPkxiImiC4KEuNHEwWJcbPyoYiyQLgsyKJwDpIoNiY2TUyYxnMxsAlgOISXgYGdE827PIy0CEUAdlAEbg1NcZ0AAAAASUVORK5CYII=);
12 }
13 }
14
15 li.close {
16 span.arrowUnderlay {
17 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUBAMAAAB/pwA+AAAAMFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABaPxwLAAAAD3RSTlMAAQIECiMlYWJ3psPc3v2CpcpnAAAARklEQVQIW2NgIAgUoLQBg9QVCIvjGUP8Xwcws/83A8d/sDCY6gcLg0kwHyoHEoBIgUSggiDh+VBjgMIwQZghYMB+hIF8AABJKyB+OnNcUQAAAABJRU5ErkJggg==);
18 }
19 }
20
21 &.none {
22 span.arrowUnderlay {
23 display: none;
24 }
25 }
26
27
28 &.left {
29 li {
30 list-style-type: none;
31 }
32
33 span.arrowUnderlay {
34 position: absolute;
35 left: 1.3em;
36 }
37 }
38
39 &.right {
40 span.arrowUnderlay {
41 float: right;
42 }
43 }
44}
45}
diff --git a/public_html/lib/plugins/navi/syntax.php b/public_html/lib/plugins/navi/syntax.php
new file mode 100644
index 00000000..eb75e2f4
--- /dev/null
+++ b/public_html/lib/plugins/navi/syntax.php
@@ -0,0 +1,241 @@
1<?php
2/**
3 * Build a navigation menu from a list
4 *
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <gohr@cosmocode.de>
7 */
8// must be run within Dokuwiki
9if(!defined('DOKU_INC')) die();
10
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12require_once(DOKU_PLUGIN.'syntax.php');
13
14class syntax_plugin_navi extends DokuWiki_Syntax_Plugin {
15
16 /**
17 * What kind of syntax are we?
18 */
19 function getType(){
20 return 'substition';
21 }
22
23 /**
24 * What about paragraphs?
25 */
26 function getPType(){
27 return 'block';
28 }
29
30 /**
31 * Where to sort in?
32 */
33 function getSort(){
34 return 155;
35 }
36
37 /**
38 * Connect pattern to lexer
39 */
40 function connectTo($mode) {
41 $this->Lexer->addSpecialPattern('{{navi>[^}]+}}',$mode,'plugin_navi');
42 }
43
44 /**
45 * Handle the match
46 */
47 function handle($match, $state, $pos, Doku_Handler $handler){
48 global $ID;
49
50 $id = substr($match,7,-2);
51 list($id,$opt) = explode('?',$id,2);
52 $id = cleanID($id);
53
54 // fetch the instructions of the control page
55 $instructions = p_cached_instructions(wikiFN($id),false,$id);
56
57 // prepare some vars
58 $max = count($instructions);
59 $pre = true;
60 $lvl = 0;
61 $parents = array();
62 $page = '';
63 $cnt = 0;
64
65 // build a lookup table
66 for($i=0; $i<$max; $i++){
67 if($instructions[$i][0] == 'listu_open'){
68 $pre = false;
69 $lvl++;
70 if($page) array_push($parents,$page);
71 }elseif($instructions[$i][0] == 'listu_close'){
72 $lvl--;
73 array_pop($parents);
74 }elseif($pre || $lvl == 0){
75 unset($instructions[$i]);
76 }elseif($instructions[$i][0] == 'listitem_close'){
77 $cnt++;
78 }elseif($instructions[$i][0] == 'internallink'){
79 $foo = true;
80 $page = $instructions[$i][1][0];
81 resolve_pageid(getNS($ID),$page,$foo); // resolve relative to sidebar ID
82 $list[$page] = array(
83 'parents' => $parents,
84 'page' => $page,
85 'title' => $instructions[$i][1][1],
86 'lvl' => $lvl
87 );
88 } elseif ($instructions[$i][0] == 'externallink') {
89 $url = $instructions[$i][1][0];
90 $list['_'.$page] = array(
91 'parents' => $parents,
92 'page' => $url,
93 'title' => $instructions[$i][1][1],
94 'lvl' => $lvl
95 );
96 }
97 }
98 return array(wikiFN($id),$list,$opt);
99 }
100
101 /**
102 * Create output
103 *
104 * We handle all modes (except meta) because we pass all output creation back to the parent
105 */
106 function render($format, Doku_Renderer $R, $data) {
107 $fn = $data[0];
108 $opt = $data[2];
109 $data = $data[1];
110
111 if($format == 'metadata'){
112 $R->meta['relation']['naviplugin'][] = $fn;
113 return true;
114 }
115
116 $R->info['cache'] = false; // no cache please
117
118 $path = $this->getOpenPath($data, $opt);
119 $arrowLocation = $this->getConf('arrow');
120
121 $R->doc .= '<div class="plugin__navi ' . $arrowLocation . '">';
122 $this->renderTree($data, $path, $R);
123 $R->doc .= '</div>';
124
125 return true;
126 }
127
128 public function getOpenPath($data, $opt) {
129 global $INFO;
130 $openPath = array();
131 if(isset($data[$INFO['id']])){
132 $openPath = (array) $data[$INFO['id']]['parents']; // get the "path" of the page we're on currently
133 array_push($openPath,$INFO['id']);
134 }elseif($opt == 'ns'){
135 $ns = $INFO['id'];
136
137 // traverse up for matching namespaces
138 if($data) do {
139 $ns = getNS($ns);
140 $try = "$ns:";
141 resolve_pageid('',$try,$foo);
142 if(isset($data[$try])){
143 // got a start page
144 $openPath = (array) $data[$try]['parents'];
145 array_push($openPath,$try);
146 break;
147 }else{
148 // search for the first page matching the namespace
149 foreach($data as $key => $junk){
150 if(getNS($key) == $ns){
151 $openPath = (array) $data[$key]['parents'];
152 array_push($openPath,$key);
153 break 2;
154 }
155 }
156 }
157
158 }while($ns);
159 }
160 return $openPath;
161 }
162
163 /**
164 * @param $data
165 * @param $parent
166 * @param Doku_Renderer $R
167 */
168 public function renderTree($data, $parent, Doku_Renderer $R) {
169// create a correctly nested list (or so I hope)
170 $open = false;
171 $lvl = 1;
172 $R->listu_open();
173
174 // read if item has childs and if it is open or closed
175 $upper = array();
176 foreach ((array)$data as $pid => $info) {
177 $state = (array_diff($info['parents'], $parent)) ? 'close' : '';
178 $countparents = count($info['parents']);
179 if ($countparents > '0') {
180 for ($i = 0; $i < $countparents; $i++) {
181 $upperlevel = $countparents - 1;
182 $upper[$info['parents'][$upperlevel]] = ($state == 'close') ? 'close' : 'open';
183 }
184 }
185 }
186 unset($pid);
187
188 foreach ((array)$data as $pid => $info) {
189 // only show if we are in the "path"
190 if (array_diff($info['parents'], $parent)) {
191 continue;
192 }
193 if ($upper[$pid]) {
194 $menuitem = ($upper[$pid] == 'open') ? 'open' : 'close';
195 } else {
196 $menuitem = '';
197 }
198
199 // skip every non readable page
200 if (auth_quickaclcheck(cleanID($info['page'])) < AUTH_READ) {
201 continue;
202 }
203
204 if ($info['lvl'] == $lvl) {
205 if ($open) {
206 $R->listitem_close();
207 }
208 $R->listitem_open($lvl . ' ' . $menuitem);
209 $open = true;
210 } elseif ($lvl > $info['lvl']) {
211 for ($lvl; $lvl > $info['lvl']; --$lvl) {
212 $R->listitem_close();
213 $R->listu_close();
214 }
215 $R->listitem_close();
216 $R->listitem_open($lvl . ' ' . $menuitem);
217 } elseif ($lvl < $info['lvl']) {
218 // more than one run is bad nesting!
219 for ($lvl; $lvl < $info['lvl']; ++$lvl) {
220 $R->listu_open();
221 $R->listitem_open($lvl + 1 . ' ' . $menuitem);
222 $open = true;
223 }
224 }
225
226 $R->listcontent_open();
227 if (substr($pid, 0, 1) != '_') {
228 $R->internallink(':' . $info['page'], $info['title']);
229 } else {
230 $R->externallink($info['page'], $info['title']);
231 }
232
233 $R->listcontent_close();
234 }
235 while ($lvl > 0) {
236 $R->listitem_close();
237 $R->listu_close();
238 --$lvl;
239 }
240 }
241}
diff --git a/public_html/lib/tpl/e/css/modifications.css b/public_html/lib/tpl/e/css/modifications.css
index 18e7d906..65205259 100644
--- a/public_html/lib/tpl/e/css/modifications.css
+++ b/public_html/lib/tpl/e/css/modifications.css
@@ -106,6 +106,25 @@ h1, h2, h3, h4, h5, h6,
106 display: block; 106 display: block;
107} 107}
108 108
109.nav .close {
110 float: none;
111 font-size: inherit;
112 font-weight: normal;
113 line-height: inherit;
114 color: inherit;
115 text-shadow: inherit;
116 opacity: 1;
117 filter: none;
118}
119
120.nav .open {
121 font-weight: bold;
122}
123
124.nav .open ul {
125 font-weight: normal;
126}
127
109@media (min-width: 768px) and (max-width: 993px) { 128@media (min-width: 768px) and (max-width: 993px) {
110 .bs-sidebar { 129 .bs-sidebar {
111 margin-top: 50px; 130 margin-top: 50px;