[TikiWiki-commits] [Git][tikiwiki/tiki][27.x] [BP][FIX] Wiki Parser: Ensure rendering of collapsible lists

"Domeshow Emmanuel \(@Domeshow\) via TikiWiki-cvs" <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <68a5f3fe3d680_2cd6d6c1327@gitlab-sidekiq-low-urgency-cpu-bound-v2-579cf6b8b8-x96v2.mail>

Domeshow Emmanuel pushed to branch 27.x at Tiki Wiki CMS Groupware / Tiki


Commits:
45ed34c7 by MAGENE Sem Joel at 2025-08-20T19:06:05+03:00
[BP][FIX] Wiki Parser: Ensure rendering of collapsible lists
---
* [BP][FIX] Wiki Parser: Ensure rendering of collapsible lists
---
* [BP][FIX] Wiki Parser: Ensure rendering of collapsible lists
---
* [FIX] Wiki Parser: Ensure rendering of collapsible lists
---
* [FIX] Wiki Parser: Ensure rendering of collapsible lists

See merge request tikiwiki/tiki!8300

(cherry picked from commit 1cc771022d50669c33b9b30a58c000028c2ffcf8)

See merge request tikiwiki/tiki!8333

(cherry picked from commit ba9d3715bfd25e506da1dae828fd26b314fd4018)

See merge request tikiwiki/tiki!8346

(cherry picked from commit 553c64f5e13890da44c199c4476cfbd2938abb95)

See merge request tikiwiki/tiki!8348

- - - - -


2 changed files:

- lib/parser/parserlib.php
- lib/test/TikiLib/WikiParserTest.php


Changes:

=====================================
lib/parser/parserlib.php
=====================================
@@ -1402,10 +1402,15 @@ class ParserLib extends TikiDb_Bridge
         }
         // Close open lists
         if ($close_lists) {
+            $did_close_list = (count($listbeg) > 0);
             while (count($listbeg)) {
                 $data .= array_shift($listbeg);
                 $closed++;
             }
+             global $prefs;
+            if ($did_close_list && $prefs['feature_wiki_paragraph_formatting'] == 'n') {
+                $data .= '<br />';
+            }
         }
 
         // Close open divs
@@ -2425,6 +2430,7 @@ class ParserLib extends TikiDb_Bridge
         $all_anchors = [];
         $nb_last_hdr = 0;
         $nb_hdrs = 0;
+        $nb_lists = 0;
         $inTable = 0;
         $inPre = 0;
         $inComment = 0;
@@ -2441,7 +2447,8 @@ class ParserLib extends TikiDb_Bridge
             if (isset($current_title_num)) { // Exclude the first line
                 $data .= "\n";
             }
-
+            $flipper_html = '';
+            $child_list_html = '';
             $current_title_num = '';
             $numbering_remove = 0;
 
@@ -2568,42 +2575,43 @@ class ParserLib extends TikiDb_Bridge
                             $liclose = '';
                         }
                     } elseif ($listlevel > count($listbeg)) {
-                        $listyle = '';
                         while ($listlevel != count($listbeg)) {
+                            $data .= ($litype == '*' ? "<ul>" : "<ol>");
                             array_unshift($listbeg, ($litype == '*' ? '</ul>' : '</ol>'));
-                            if ($listlevel == count($listbeg)) {
-                                $listate = substr($line, $listlevel, 1);
-                                if (($listate == '+' || $listate == '-') && ! ($litype == '*' && ! strstr(current($listbeg), '</ul>') || $litype == '#' && ! strstr(current($listbeg), '</ol>'))) {
-                                    $thisid = 'id' . microtime(true) * 1000000;
-                                    if (! $this->option['wysiwyg']) {
-                                        $data .= '<br /><a id="flipper' . $thisid . '" class="link" href="javascript:flipWithSign(\'' . $thisid . '\')">[' . ($listate == '-' ? '+' : '-') . ']</a>';
-                                    }
-                                    $listyle = ' id="' . $thisid . '" style="display:' . ($listate == '+' || $this->option['wysiwyg'] ? 'block' : 'none') . ';"';
-                                    $addremove = 1;
-                                }
-                            }
-                            $data .= ($litype == '*' ? "<ul$listyle>" : "<ol$listyle>");
                         }
                         $liclose = '';
                     }
+                    if (count($listbeg) && substr(current($listbeg), 0, 5) != '</li>') {
+                        $liclose = '';
+                    }
                     if ($litype == '*' && ! strstr(current($listbeg), '</ul>') || $litype == '#' && ! strstr(current($listbeg), '</ol>')) {
                         $data .= array_shift($listbeg);
-                        $listyle = '';
-                        $listate = substr($line, $listlevel, 1);
-                        if (($listate == '+' || $listate == '-')) {
-                            $thisid = 'id' . microtime() * 1000000;
-                            if (! $this->option['wysiwyg']) {
-                                $data .= '<br /><a id="flipper' . $thisid . '" class="link" href="javascript:flipWithSign(\'' . $thisid . '\')">[' . ($listate == '-' ? '+' : '-') . ']</a>';
-                            }
-                            $listyle = ' id="' . $thisid . '" style="display:' . ($listate == '+' || $this->option['wysiwyg'] ? 'block' : 'none') . ';"';
-                            $addremove = 1;
-                        }
-                        $data .= ($litype == '*' ? "<ul$listyle>" : "<ol$listyle>");
+                        $data .= ($litype == '*' ? "<ul>" : "<ol>"); // Open a PLAIN list
                         $liclose = '';
-                        array_unshift($listbeg, ($litype == '*' ? '</li></ul>' : '</li></ol>'));
+                        array_unshift($listbeg, ($litype == '*' ? '</ul></li>' : '</ol></li>'));
                     }
-                    $line = $liclose . '<li>' . substr($line, $listlevel + $addremove);
-                    if (substr(current($listbeg), 0, 5) != '</li>') {
+
+                    // Step A: Check for +/- sign and PREPARE the HTML pieces in variables.
+                    $listate = substr($line, $listlevel, 1);
+                    if (($listate == '+' || $listate == '-')) {
+                        $nb_lists++;
+                        $thisid = 'id' . preg_replace('/[^a-zA-Z0-9]/', '', urlencode($this->option['page'] ?? '')) . $nb_lists;
+                        if (! $this->option['wysiwyg']) {
+                            // 1. Prepare the flipper link
+                            $flipper_html = '<a id="flipper' . $thisid . '" class="link" href="javascript:flipWithSign(\'' . $thisid . '\')">[' . ($listate == '-' ? '+' : '-') . ']</a>';
+                            // 2. Prepare the child list container with the correct style
+                            $child_list_html = ($litype == '*') ? '<ul id="' . $thisid . '" style="display:' . ($listate == '+' ? 'block' : 'none') . ';">' : '<ol id="' . $thisid . '" style="display:' . ($listate == '+' ? 'block' : 'none') . ';">';
+                        }
+                        $addremove = 1;
+                    }
+
+                    // Step B: ASSEMBLE the final line from the prepared pieces.
+                    $line = $liclose . '<li>' . $flipper_html . substr($line, $listlevel + $addremove) . $child_list_html;
+
+                     // Step C: MANAGE the state stack correctly and exclusively.
+                    if ($child_list_html) {
+                        array_unshift($listbeg, ($litype == '*' ? '</ul></li>' : '</ol></li>'));
+                    } elseif (! str_starts_with(current($listbeg), '</li>')) {
                         array_unshift($listbeg, '</li>' . array_shift($listbeg));
                     }
                 } elseif ($litype == '+') {
@@ -2633,7 +2641,9 @@ class ParserLib extends TikiDb_Bridge
                     // but not paragraph or div's. If we are
                     // closing a list, there really shouldn't be a
                     // paragraph open anyway.
-                    $this->close_blocks($data, $in_paragraph, $listbeg, $divdepth, 0, 1, 0);
+                    if (trim($line) !== '') {
+                        $this->close_blocks($data, $in_paragraph, $listbeg, $divdepth, 0, 1, 0);
+                    }
 
                     // Get count of (possible) header signs at start
                     $hdrlevel = $tikilib->how_many_at_start($line, '!');
@@ -2897,7 +2907,10 @@ class ParserLib extends TikiDb_Bridge
                                       // }
                                 }
                             } else {
-                                $line .= "<br />";
+                                // This is the legacy line break : Only add this break if we are NOT currently inside a list.
+                                if (count($listbeg) == 0) {
+                                    $line .= "<br />";
+                                }
                             }
                         }
                     }
@@ -2925,6 +2938,7 @@ class ParserLib extends TikiDb_Bridge
         }
 
         // Close open paragraph, lists, and div's
+
         $this->close_blocks($data, $in_paragraph, $listbeg, $divdepth, 1, 1, 1);
 
         /*


=====================================
lib/test/TikiLib/WikiParserTest.php
=====================================
@@ -104,6 +104,36 @@ class TikiLib_WikiParserTest extends PHPUnit\Framework\TestCase
             ["# foo1\n## foo11\n##foo12\n# bar1\n", "<ol><li> foo1\n<ol><li> foo11\n</li><li>foo12\n</li></ol></li><li> bar1\n</li></ol><br />"],   // Nested Numbered list
             ["# foo\n+ Continuation1\n+Continuation2\n# bar\n", "<ol><li> foo\n<br /> Continuation1\n<br />Continuation2\n</li><li> bar\n</li></ol><br />"], // Numbered list with continuation
 
+            // --- TESTS FOR COLLAPSIBLE LISTS ---
+
+            // Test 1: Basic collapsible list, shown by default (+)
+            [
+                "*+ Collapsible List Item",
+                '<ul><li><a id="flipperidHomePage1" class="link" href="javascript:flipWithSign(\'idHomePage1\')">[-]</a> Collapsible List Item<ul id="idHomePage1" style="display:block;"></ul></li></ul><br />',
+                ['page' => 'HomePage']
+            ],
+
+            // Test 2: Basic collapsible list, hidden by default (-)
+            [
+                "*- Collapsible List Item",
+                '<ul><li><a id="flipperidHomePage1" class="link" href="javascript:flipWithSign(\'idHomePage1\')">[+]</a> Collapsible List Item<ul id="idHomePage1" style="display:none;"></ul></li></ul><br />',
+                ['page' => 'HomePage']
+            ],
+
+            // Test 3: Nested collapsible list with children
+            [
+                "*+ Parent\n**- Child\n*** Grandchild",
+                '<ul><li><a id="flipperidHomePage1" class="link" href="javascript:flipWithSign(\'idHomePage1\')">[-]</a> Parent<ul id="idHomePage1" style="display:block;">' . "\n" . '<li><a id="flipperidHomePage2" class="link" href="javascript:flipWithSign(\'idHomePage2\')">[+]</a> Child<ul id="idHomePage2" style="display:none;">' . "\n" . '<li> Grandchild</li></ul></li></ul></li></ul><br />',
+                ['page' => 'HomePage']
+            ],
+
+            // Test 4: Ensure blank lines do not break a nested list
+            [
+                "*+ Parent\n\n** Child",
+                '<ul><li><a id="flipperidHomePage1" class="link" href="javascript:flipWithSign(\'idHomePage1\')">[-]</a> Parent<ul id="idHomePage1" style="display:block;">' . "\n\n" . '<li> Child</li></ul></li></ul><br />',
+                ['page' => 'HomePage']
+            ],
+
             ["||r1c1|r1c2\nr2c1|r2c2||", '<table class="wikitable table table-striped table-hover"><tr><td class="wikicell" >r1c1</td><td class="wikicell" >r1c2</td></tr><tr><td class="wikicell" >r2c1</td><td class="wikicell" >r2c2</td></tr></table><br />'],
             ["~pp~foo~/pp~", "<pre>foo</pre><br />"],
         ];



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/45ed34c7c36cefe37cf4a81a512b6feb88f92fd4

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/45ed34c7c36cefe37cf4a81a512b6feb88f92fd4
You're receiving this email because of your account on gitlab.com.

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.