xref: /plugin/combo/ComboStrap/PageExplorerTag.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1*04fd306cSNickeau<?php
2*04fd306cSNickeau
3*04fd306cSNickeaunamespace ComboStrap;
4*04fd306cSNickeau
5*04fd306cSNickeau
6*04fd306cSNickeauuse ComboStrap\TagAttribute\StyleAttribute;
7*04fd306cSNickeauuse Doku_Handler;
8*04fd306cSNickeau
9*04fd306cSNickeau
10*04fd306cSNickeauclass PageExplorerTag
11*04fd306cSNickeau{
12*04fd306cSNickeau    public const PAGE_TYPE = "page";
13*04fd306cSNickeau    public const FOLDER_ICON = "images:page-explorer-folder";
14*04fd306cSNickeau    /**
15*04fd306cSNickeau     * Page canonical and tag pattern
16*04fd306cSNickeau     */
17*04fd306cSNickeau    public const CANONICAL = "page-explorer";
18*04fd306cSNickeau    public const HOME_TYPE = "home";
19*04fd306cSNickeau    public const PAGE_ATTRIBUTES = "page-attributes";
20*04fd306cSNickeau    public const INDEX_INSTRUCTIONS = "index-instructions";
21*04fd306cSNickeau    public const NAMESPACE_ATTRIBUTES = "namespace-attributes";
22*04fd306cSNickeau    public const TYPE_TREE = "tree";
23*04fd306cSNickeau    public const PAGE_INSTRUCTIONS = "page-instructions";
24*04fd306cSNickeau    public const PARENT_ATTRIBUTES = "parent-attributes";
25*04fd306cSNickeau    public const INDEX_ATTRIBUTES = "index-attributes";
26*04fd306cSNickeau    public const NAMESPACE_INSTRUCTIONS = "namespace-instructions";
27*04fd306cSNickeau    /**
28*04fd306cSNickeau     * Tag in Dokuwiki cannot have a `-`
29*04fd306cSNickeau     * This is the last part of the class
30*04fd306cSNickeau     */
31*04fd306cSNickeau    public const LOGICAL_TAG = self::PAGE_EXPLORER_MARKUP;
32*04fd306cSNickeau    /**
33*04fd306cSNickeau     * Namespace attribute
34*04fd306cSNickeau     * that contains the namespace information
35*04fd306cSNickeau     * (ie
36*04fd306cSNickeau     *   * a namespace path
37*04fd306cSNickeau     *   * or current, for the namespace of the current requested page
38*04fd306cSNickeau     */
39*04fd306cSNickeau    public const ATTR_NAMESPACE = "ns";
40*04fd306cSNickeau    public const LEVEL_UP_ICON = "images:page-explorer-icons8-level-up";
41*04fd306cSNickeau
42*04fd306cSNickeau    public const NTOC_MARKUP = "ntoc";
43*04fd306cSNickeau    public const PAGE_EXPLORER_MARKUP = "page-explorer";
44*04fd306cSNickeau
45*04fd306cSNickeau    public const PARENT_INSTRUCTIONS = "parent-instructions";
46*04fd306cSNickeau    /**
47*04fd306cSNickeau     * Attributes on the home node
48*04fd306cSNickeau     */
49*04fd306cSNickeau    public const LIST_TYPE = "list";
50*04fd306cSNickeau    public const INDEX_TAG = "index";
51*04fd306cSNickeau    /**
52*04fd306cSNickeau     * The pattern
53*04fd306cSNickeau     */
54*04fd306cSNickeau    public const INDEX_HOME_TAG = "home";
55*04fd306cSNickeau    /**
56*04fd306cSNickeau     * Tag in Dokuwiki cannot have a `-`
57*04fd306cSNickeau     * This is the last part of the class
58*04fd306cSNickeau     */
59*04fd306cSNickeau    public const LOGICAL_INDEX_TAG = "pageexplorerhome";
60*04fd306cSNickeau    public const INDEXES_TAG = [PageExplorerTag::INDEX_HOME_TAG, PageExplorerTag::INDEX_TAG];
61*04fd306cSNickeau    /**
62*04fd306cSNickeau     * Implementation of the namespace
63*04fd306cSNickeau     *   * ie the button (in a collapsible menu) http://localhost:63342/bootstrap-5.0.1-examples/sidebars/index.html
64*04fd306cSNickeau     *   * or the directory in a list menu
65*04fd306cSNickeau     *
66*04fd306cSNickeau     * This syntax is not a classic syntax plugin
67*04fd306cSNickeau     * The instructions are captured at the {@link DOKU_LEXER_END}
68*04fd306cSNickeau     * state of {@link syntax_plugin_combo_pageexplorer::handle()}
69*04fd306cSNickeau     * to create/generate the namespaces
70*04fd306cSNickeau     *
71*04fd306cSNickeau     */
72*04fd306cSNickeau    public const NAMESPACE_LOGICAL_TAG = "pageexplorernamespace";
73*04fd306cSNickeau    public const NAMESPACE_SHORT_TAG = "ns";
74*04fd306cSNickeau    public const NAMESPACE_ITEM_TAG = "ns-item";
75*04fd306cSNickeau    public const NAMESPACE_LONG_TAG = "namespace";
76*04fd306cSNickeau    /**
77*04fd306cSNickeau     * Tag in Dokuwiki cannot have a `-`
78*04fd306cSNickeau     * This is the last part of the class
79*04fd306cSNickeau     */
80*04fd306cSNickeau    public const PAGE_LOGICAL_TAG = self::PAGE_TAG;
81*04fd306cSNickeau    /**
82*04fd306cSNickeau     * The pattern
83*04fd306cSNickeau     */
84*04fd306cSNickeau    public const PAGE_TAG = "page";
85*04fd306cSNickeau    public const PAGE_ITEM_TAG = "page-item";
86*04fd306cSNickeau    const PARENT_TAG = "parent";
87*04fd306cSNickeau
88*04fd306cSNickeau
89*04fd306cSNickeau    /**
90*04fd306cSNickeau     * @param string $html
91*04fd306cSNickeau     * @param MarkupPath $page
92*04fd306cSNickeau     * @param array $data - the data array from the handler
93*04fd306cSNickeau     * @param string $type
94*04fd306cSNickeau     */
95*04fd306cSNickeau    public static function treeProcessLeaf(string &$html, MarkupPath $page, array $data, string $type)
96*04fd306cSNickeau    {
97*04fd306cSNickeau        /**
98*04fd306cSNickeau         * In callstack instructions
99*04fd306cSNickeau         * <li>
100*04fd306cSNickeau         *   $instructions
101*04fd306cSNickeau         * </li>
102*04fd306cSNickeau         */
103*04fd306cSNickeau        $pageAttributes = $data[self::PAGE_ATTRIBUTES];
104*04fd306cSNickeau        $pageInstructions = $data[self::PAGE_INSTRUCTIONS];
105*04fd306cSNickeau        if ($pageInstructions === null && $pageAttributes !== null) {
106*04fd306cSNickeau            return;
107*04fd306cSNickeau        }
108*04fd306cSNickeau        if (!FileSystems::exists($page->getPathObject())) {
109*04fd306cSNickeau            LogUtility::error("The given leaf page ($page) does not exist and was not added to the page-explorer tree", self::CANONICAL);
110*04fd306cSNickeau            return;
111*04fd306cSNickeau        }
112*04fd306cSNickeau        if ($page->isHidden()) {
113*04fd306cSNickeau            return;
114*04fd306cSNickeau        }
115*04fd306cSNickeau
116*04fd306cSNickeau        $listItemEnterTag = TagAttributes::createEmpty()
117*04fd306cSNickeau            ->setLogicalTag(self::CANONICAL . "-tree-$type")
118*04fd306cSNickeau            ->toHtmlEnterTag("li");
119*04fd306cSNickeau
120*04fd306cSNickeau        $listItemContent = "";
121*04fd306cSNickeau        if ($pageInstructions !== null) {
122*04fd306cSNickeau            try {
123*04fd306cSNickeau                $listItemContent = MarkupRenderUtility::renderInstructionsToXhtml($pageInstructions, $page->getMetadataForRendering());
124*04fd306cSNickeau            } catch (ExceptionCompile $e) {
125*04fd306cSNickeau                LogUtility::error("Error while rendering the leaf. Error: {$e->getMessage()}", self::CANONICAL);
126*04fd306cSNickeau                return;
127*04fd306cSNickeau            }
128*04fd306cSNickeau        } else {
129*04fd306cSNickeau            try {
130*04fd306cSNickeau                $listItemContent = LinkMarkup::createFromPageIdOrPath($page->getWikiId())
131*04fd306cSNickeau                    ->toAttributes()
132*04fd306cSNickeau                    ->toHtmlEnterTag("a");
133*04fd306cSNickeau                $listItemContent .= "{$page->getNameOrDefault()}</a>";
134*04fd306cSNickeau            } catch (ExceptionCompile $e) {
135*04fd306cSNickeau                LogUtility::error("Error while rendering the default tree page. Error: {$e->getMessage()}", self::CANONICAL);
136*04fd306cSNickeau            }
137*04fd306cSNickeau        }
138*04fd306cSNickeau        /** @noinspection PhpUnnecessaryCurlyVarSyntaxInspection */
139*04fd306cSNickeau        $html .= "{$listItemEnterTag}{$listItemContent}</li>";
140*04fd306cSNickeau
141*04fd306cSNickeau    }
142*04fd306cSNickeau
143*04fd306cSNickeau    /**
144*04fd306cSNickeau     * @param WikiPath $namespacePath
145*04fd306cSNickeau     * @return string the last part with a uppercase letter and where underscore became a space
146*04fd306cSNickeau     */
147*04fd306cSNickeau    public static function toNamespaceName(WikiPath $namespacePath): string
148*04fd306cSNickeau    {
149*04fd306cSNickeau        try {
150*04fd306cSNickeau            return ucfirst(trim(str_replace("_", " ", $namespacePath->getLastNameWithoutExtension())));
151*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
152*04fd306cSNickeau            // root
153*04fd306cSNickeau            return "";
154*04fd306cSNickeau        }
155*04fd306cSNickeau    }
156*04fd306cSNickeau
157*04fd306cSNickeau    /**
158*04fd306cSNickeau     * A class prefix added in elements
159*04fd306cSNickeau     * @param string $type
160*04fd306cSNickeau     * @return string
161*04fd306cSNickeau     */
162*04fd306cSNickeau    public static function getClassPrefix(string $type): string
163*04fd306cSNickeau    {
164*04fd306cSNickeau        return self::CANONICAL . "-$type";
165*04fd306cSNickeau    }
166*04fd306cSNickeau
167*04fd306cSNickeau    public static function handleExit(Doku_Handler $handler)
168*04fd306cSNickeau    {
169*04fd306cSNickeau        $callStack = CallStack::createFromHandler($handler);
170*04fd306cSNickeau
171*04fd306cSNickeau        /**
172*04fd306cSNickeau         * Capture the instructions for
173*04fd306cSNickeau         * {@link syntax_plugin_combo_pageexplorerpage}
174*04fd306cSNickeau         * {@link syntax_plugin_combo_pageexplorernamespace}
175*04fd306cSNickeau         * {@link syntax_plugin_combo_pageexplorernamehome}
176*04fd306cSNickeau         */
177*04fd306cSNickeau        $openingTag = $callStack->moveToPreviousCorrespondingOpeningCall();
178*04fd306cSNickeau        /**
179*04fd306cSNickeau         * @var Call[] $namespaceInstructions
180*04fd306cSNickeau         * @var array $namespaceAttributes
181*04fd306cSNickeau         */
182*04fd306cSNickeau        $namespaceInstructions = null;
183*04fd306cSNickeau        $namespaceAttributes = null;
184*04fd306cSNickeau        /**
185*04fd306cSNickeau         * @var Call[] $templatePageInstructions
186*04fd306cSNickeau         * @var array $pageAttributes
187*04fd306cSNickeau         */
188*04fd306cSNickeau        $templatePageInstructions = null;
189*04fd306cSNickeau        $pageAttributes = null;
190*04fd306cSNickeau        /**
191*04fd306cSNickeau         * @var Call[] $templateHomeInstructions
192*04fd306cSNickeau         * @var array $homeAttributes
193*04fd306cSNickeau         */
194*04fd306cSNickeau        $templateHomeInstructions = null;
195*04fd306cSNickeau        $homeAttributes = null;
196*04fd306cSNickeau        /**
197*04fd306cSNickeau         * The instructions for the parent item in a page explorer list
198*04fd306cSNickeau         * if any
199*04fd306cSNickeau         * @var Call[] $parentInstructions
200*04fd306cSNickeau         * @var array $parentAttributes
201*04fd306cSNickeau         */
202*04fd306cSNickeau        $parentInstructions = null;
203*04fd306cSNickeau        $parentAttributes = null;
204*04fd306cSNickeau        /**
205*04fd306cSNickeau         * @var Call[] $actualInstructionsStack
206*04fd306cSNickeau         */
207*04fd306cSNickeau        $actualInstructionsStack = [];
208*04fd306cSNickeau        while ($callStack->next()) {
209*04fd306cSNickeau            $actualCall = $callStack->getActualCall();
210*04fd306cSNickeau            $tagName = $actualCall->getTagName();
211*04fd306cSNickeau            switch ($actualCall->getState()) {
212*04fd306cSNickeau                case DOKU_LEXER_ENTER:
213*04fd306cSNickeau                    switch ($tagName) {
214*04fd306cSNickeau                        case self::PAGE_LOGICAL_TAG:
215*04fd306cSNickeau                            $pageAttributes = $actualCall->getAttributes();
216*04fd306cSNickeau                            continue 3;
217*04fd306cSNickeau                        case self::NAMESPACE_LOGICAL_TAG:
218*04fd306cSNickeau                            $namespaceAttributes = $actualCall->getAttributes();
219*04fd306cSNickeau                            continue 3;
220*04fd306cSNickeau                        case self::LOGICAL_INDEX_TAG:
221*04fd306cSNickeau                            $homeAttributes = $actualCall->getAttributes();
222*04fd306cSNickeau                            continue 3;
223*04fd306cSNickeau                        case self::PARENT_TAG:
224*04fd306cSNickeau                            $parentAttributes = $actualCall->getAttributes();
225*04fd306cSNickeau                            continue 3;
226*04fd306cSNickeau                        default:
227*04fd306cSNickeau                            $actualInstructionsStack[] = $actualCall->toCallArray();
228*04fd306cSNickeau                            continue 3;
229*04fd306cSNickeau                    }
230*04fd306cSNickeau                case DOKU_LEXER_EXIT:
231*04fd306cSNickeau                    switch ($tagName) {
232*04fd306cSNickeau                        case self::PAGE_LOGICAL_TAG:
233*04fd306cSNickeau                            $templatePageInstructions = $actualInstructionsStack;
234*04fd306cSNickeau                            $actualInstructionsStack = [];
235*04fd306cSNickeau                            continue 3;
236*04fd306cSNickeau                        case self::NAMESPACE_LOGICAL_TAG:
237*04fd306cSNickeau                            $namespaceInstructions = $actualInstructionsStack;
238*04fd306cSNickeau                            $actualInstructionsStack = [];
239*04fd306cSNickeau                            continue 3;
240*04fd306cSNickeau                        case self::LOGICAL_INDEX_TAG:
241*04fd306cSNickeau                            $templateHomeInstructions = $actualInstructionsStack;
242*04fd306cSNickeau                            $actualInstructionsStack = [];
243*04fd306cSNickeau                            continue 3;
244*04fd306cSNickeau                        case PageExplorerTag::PARENT_TAG:
245*04fd306cSNickeau                            $parentInstructions = $actualInstructionsStack;
246*04fd306cSNickeau                            $actualInstructionsStack = [];
247*04fd306cSNickeau                            continue 3;
248*04fd306cSNickeau                        default:
249*04fd306cSNickeau                            $actualInstructionsStack[] = $actualCall->toCallArray();
250*04fd306cSNickeau                            continue 3;
251*04fd306cSNickeau
252*04fd306cSNickeau                    }
253*04fd306cSNickeau                default:
254*04fd306cSNickeau                    $actualInstructionsStack[] = $actualCall->toCallArray();
255*04fd306cSNickeau                    break;
256*04fd306cSNickeau
257*04fd306cSNickeau            }
258*04fd306cSNickeau        }
259*04fd306cSNickeau        /**
260*04fd306cSNickeau         * Remove all callstack from the opening tag
261*04fd306cSNickeau         */
262*04fd306cSNickeau        $callStack->deleteAllCallsAfter($openingTag);
263*04fd306cSNickeau
264*04fd306cSNickeau        /**
265*04fd306cSNickeau         * The container/block should have at minimum an enter tag
266*04fd306cSNickeau         * to be able to set the {@link action_plugin_combo_sideslotpostprocessing} auto collapsible
267*04fd306cSNickeau         * parameter
268*04fd306cSNickeau         */
269*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::NAMESPACE_INSTRUCTIONS, $namespaceInstructions);
270*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::NAMESPACE_ATTRIBUTES, $namespaceAttributes);
271*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::PAGE_INSTRUCTIONS, $templatePageInstructions);
272*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::PAGE_ATTRIBUTES, $pageAttributes);
273*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::INDEX_INSTRUCTIONS, $templateHomeInstructions);
274*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::INDEX_ATTRIBUTES, $homeAttributes);
275*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::PARENT_INSTRUCTIONS, $parentInstructions);
276*04fd306cSNickeau        $openingTag->setPluginData(PageExplorerTag::PARENT_ATTRIBUTES, $parentAttributes);
277*04fd306cSNickeau    }
278*04fd306cSNickeau
279*04fd306cSNickeau    public static function renderEnterTag(TagAttributes $pageExplorerTagAttributes, array $data)
280*04fd306cSNickeau    {
281*04fd306cSNickeau
282*04fd306cSNickeau        $returnedXhtml = "";
283*04fd306cSNickeau        /**
284*04fd306cSNickeau         * Id (id is mandatory for toggle)
285*04fd306cSNickeau         */
286*04fd306cSNickeau        $id = $pageExplorerTagAttributes->getValue(TagAttributes::ID_KEY);
287*04fd306cSNickeau        if ($id === null) {
288*04fd306cSNickeau            $id = IdManager::getOrCreate()->generateNewHtmlIdForComponent(PageExplorerTag::CANONICAL);
289*04fd306cSNickeau            $pageExplorerTagAttributes->setComponentAttributeValue(TagAttributes::ID_KEY, $id);
290*04fd306cSNickeau        }
291*04fd306cSNickeau
292*04fd306cSNickeau        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
293*04fd306cSNickeau
294*04fd306cSNickeau
295*04fd306cSNickeau        try {
296*04fd306cSNickeau
297*04fd306cSNickeau            /**
298*04fd306cSNickeau             * {@link MarkupCacheDependencies::PAGE_PRIMARY_META_DEPENDENCY}
299*04fd306cSNickeau             * The cache output is composed of primary metadata
300*04fd306cSNickeau             * (If it changes, the content change)
301*04fd306cSNickeau             *
302*04fd306cSNickeau             * {@link MarkupCacheDependencies::PAGE_SYSTEM_DEPENDENCY}
303*04fd306cSNickeau             * The content depend on the file system tree
304*04fd306cSNickeau             * (if a file is added or deleted, the content will change)
305*04fd306cSNickeau             */
306*04fd306cSNickeau            $executionContext
307*04fd306cSNickeau                ->getExecutingMarkupHandler()
308*04fd306cSNickeau                ->getOutputCacheDependencies()
309*04fd306cSNickeau                ->addDependency(MarkupCacheDependencies::PAGE_PRIMARY_META_DEPENDENCY)
310*04fd306cSNickeau                ->addDependency(MarkupCacheDependencies::PAGE_SYSTEM_DEPENDENCY);
311*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
312*04fd306cSNickeau            // no fetcher markup running
313*04fd306cSNickeau            // ie markup
314*04fd306cSNickeau        }
315*04fd306cSNickeau
316*04fd306cSNickeau        /**
317*04fd306cSNickeau         * Context
318*04fd306cSNickeau         */
319*04fd306cSNickeau        $requestedContextPath = $executionContext->getContextPath();
320*04fd306cSNickeau
321*04fd306cSNickeau        /**
322*04fd306cSNickeau         * NameSpacePath determination
323*04fd306cSNickeau         */
324*04fd306cSNickeau        $pageExplorerType = $pageExplorerTagAttributes->getType();
325*04fd306cSNickeau        $namespaceAttribute = $pageExplorerTagAttributes->getValueAndRemove(PageExplorerTag::ATTR_NAMESPACE);
326*04fd306cSNickeau        if ($namespaceAttribute !== null) {
327*04fd306cSNickeau            WikiPath::addNamespaceEndSeparatorIfNotPresent($namespaceAttribute);
328*04fd306cSNickeau            $namespacePath = WikiPath::createMarkupPathFromPath($namespaceAttribute);
329*04fd306cSNickeau        } else {
330*04fd306cSNickeau            try {
331*04fd306cSNickeau                $namespacePath = $requestedContextPath->getParent();
332*04fd306cSNickeau            } catch (ExceptionNotFound $e) {
333*04fd306cSNickeau                $namespacePath = WikiPath::createRootNamespacePathOnMarkupDrive();
334*04fd306cSNickeau            }
335*04fd306cSNickeau            try {
336*04fd306cSNickeau                $executionContext
337*04fd306cSNickeau                    ->getExecutingMarkupHandler()
338*04fd306cSNickeau                    ->getOutputCacheDependencies()
339*04fd306cSNickeau                    ->addDependency(MarkupCacheDependencies::REQUESTED_NAMESPACE_DEPENDENCY);
340*04fd306cSNickeau            } catch (ExceptionNotFound $e) {
341*04fd306cSNickeau                // ok
342*04fd306cSNickeau            }
343*04fd306cSNickeau        }
344*04fd306cSNickeau
345*04fd306cSNickeau
346*04fd306cSNickeau        /**
347*04fd306cSNickeau         * Class Prefix
348*04fd306cSNickeau         */
349*04fd306cSNickeau        $componentClassPrefix = PageExplorerTag::getClassPrefix($pageExplorerType);
350*04fd306cSNickeau
351*04fd306cSNickeau
352*04fd306cSNickeau        /**
353*04fd306cSNickeau         * Rendering
354*04fd306cSNickeau         */
355*04fd306cSNickeau        switch ($pageExplorerType) {
356*04fd306cSNickeau            default:
357*04fd306cSNickeau            case PageExplorerTag::LIST_TYPE:
358*04fd306cSNickeau
359*04fd306cSNickeau                /**
360*04fd306cSNickeau                 * Class
361*04fd306cSNickeau                 */
362*04fd306cSNickeau                $classContainer = "list-group";
363*04fd306cSNickeau                $classItem = "list-group-item";
364*04fd306cSNickeau
365*04fd306cSNickeau                /**
366*04fd306cSNickeau                 * Css
367*04fd306cSNickeau                 */
368*04fd306cSNickeau                $executionContext
369*04fd306cSNickeau                    ->getSnippetSystem()
370*04fd306cSNickeau                    ->attachCssInternalStyleSheet($componentClassPrefix);
371*04fd306cSNickeau
372*04fd306cSNickeau                /**
373*04fd306cSNickeau                 * Create the enter content list tag
374*04fd306cSNickeau                 */
375*04fd306cSNickeau                $returnedXhtml .= $pageExplorerTagAttributes
376*04fd306cSNickeau                    ->addClassName($classContainer)
377*04fd306cSNickeau                    ->removeAttributeIfPresent(TagAttributes::WIKI_ID)
378*04fd306cSNickeau                    ->setLogicalTag(PageExplorerTag::CANONICAL)
379*04fd306cSNickeau                    ->toHtmlEnterTag("ul");
380*04fd306cSNickeau
381*04fd306cSNickeau
382*04fd306cSNickeau                /**
383*04fd306cSNickeau                 * Home
384*04fd306cSNickeau                 */
385*04fd306cSNickeau                $indexInstructions = $data[PageExplorerTag::INDEX_INSTRUCTIONS];
386*04fd306cSNickeau                $indexAttributes = $data[PageExplorerTag::INDEX_ATTRIBUTES];
387*04fd306cSNickeau                $currentIndexPage = MarkupPath::createPageFromPathObject($namespacePath);
388*04fd306cSNickeau                if (!($indexInstructions === null && $indexAttributes !== null)) {
389*04fd306cSNickeau
390*04fd306cSNickeau                    if (FileSystems::exists($currentIndexPage)) {
391*04fd306cSNickeau
392*04fd306cSNickeau
393*04fd306cSNickeau                        $indexTagAttributes = TagAttributes::createFromCallStackArray($indexAttributes);
394*04fd306cSNickeau
395*04fd306cSNickeau
396*04fd306cSNickeau                        /**
397*04fd306cSNickeau                         * Enter home tag
398*04fd306cSNickeau                         */
399*04fd306cSNickeau                        $indexPageType = "index";
400*04fd306cSNickeau                        $returnedXhtml .= $indexTagAttributes
401*04fd306cSNickeau                            ->addClassName($classItem)
402*04fd306cSNickeau                            ->setLogicalTag(PageExplorerTag::CANONICAL . "-{$pageExplorerType}-{$indexPageType}")
403*04fd306cSNickeau                            ->toHtmlEnterTag("li");
404*04fd306cSNickeau                        /**
405*04fd306cSNickeau                         * Content
406*04fd306cSNickeau                         */
407*04fd306cSNickeau                        if ($indexInstructions !== null) {
408*04fd306cSNickeau                            try {
409*04fd306cSNickeau                                $returnedXhtml .= MarkupRenderUtility::renderInstructionsToXhtml($indexInstructions, $currentIndexPage->getMetadataForRendering());
410*04fd306cSNickeau                            } catch (ExceptionCompile $e) {
411*04fd306cSNickeau                                $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the home. Error: {$e->getMessage()}");
412*04fd306cSNickeau                            }
413*04fd306cSNickeau                        } else {
414*04fd306cSNickeau                            try {
415*04fd306cSNickeau                                $returnedXhtml .= LinkMarkup::createFromPageIdOrPath($currentIndexPage->getWikiId())
416*04fd306cSNickeau                                    ->toAttributes()
417*04fd306cSNickeau                                    ->toHtmlEnterTag("a");
418*04fd306cSNickeau                                $returnedXhtml .= "{$currentIndexPage->getNameOrDefault()}</a>";
419*04fd306cSNickeau                            } catch (ExceptionCompile $e) {
420*04fd306cSNickeau                                $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the default home. Error: {$e->getMessage()}");
421*04fd306cSNickeau                            }
422*04fd306cSNickeau                        }
423*04fd306cSNickeau                        /**
424*04fd306cSNickeau                         * End home tag
425*04fd306cSNickeau                         */
426*04fd306cSNickeau                        $returnedXhtml .= "</li>";
427*04fd306cSNickeau                    }
428*04fd306cSNickeau
429*04fd306cSNickeau                }
430*04fd306cSNickeau
431*04fd306cSNickeau                /**
432*04fd306cSNickeau                 * Parent ?
433*04fd306cSNickeau                 */
434*04fd306cSNickeau                $parentInstructions = $data[PageExplorerTag::PARENT_INSTRUCTIONS];
435*04fd306cSNickeau                $parentAttributes = $data[PageExplorerTag::PARENT_ATTRIBUTES];
436*04fd306cSNickeau                if (!($parentInstructions === null && $indexAttributes !== null)) {
437*04fd306cSNickeau                    try {
438*04fd306cSNickeau                        $parentPage = $currentIndexPage->getParent();
439*04fd306cSNickeau                        if ($parentPage->exists()) {
440*04fd306cSNickeau
441*04fd306cSNickeau                            $parentTagAttributes = TagAttributes::createFromCallStackArray($parentAttributes);
442*04fd306cSNickeau                            /**
443*04fd306cSNickeau                             * Enter parent tag
444*04fd306cSNickeau                             */
445*04fd306cSNickeau                            $pageType = "parent";
446*04fd306cSNickeau                            $returnedXhtml .= $parentTagAttributes
447*04fd306cSNickeau                                ->addClassName($classItem)
448*04fd306cSNickeau                                ->setLogicalTag(PageExplorerTag::CANONICAL . "-{$pageExplorerType}-{$pageType}")
449*04fd306cSNickeau                                ->toHtmlEnterTag("li");
450*04fd306cSNickeau                            /**
451*04fd306cSNickeau                             * Content
452*04fd306cSNickeau                             */
453*04fd306cSNickeau                            if ($parentInstructions !== null) {
454*04fd306cSNickeau                                try {
455*04fd306cSNickeau                                    $returnedXhtml .= MarkupRenderUtility::renderInstructionsToXhtml($parentInstructions, $parentPage->getMetadataForRendering());
456*04fd306cSNickeau                                } catch (ExceptionCompile $e) {
457*04fd306cSNickeau                                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the parent instructions. Error: {$e->getMessage()}");
458*04fd306cSNickeau                                }
459*04fd306cSNickeau                            } else {
460*04fd306cSNickeau                                try {
461*04fd306cSNickeau                                    $parentWikiId = $parentPage->getPathObject()->getWikiId();
462*04fd306cSNickeau                                    $returnedXhtml .= LinkMarkup::createFromPageIdOrPath($parentWikiId)
463*04fd306cSNickeau                                        ->toAttributes()
464*04fd306cSNickeau                                        ->toHtmlEnterTag("a");
465*04fd306cSNickeau                                    $returnedXhtml .= Icon::createFromComboResource(PageExplorerTag::LEVEL_UP_ICON)
466*04fd306cSNickeau                                        ->toHtml();
467*04fd306cSNickeau                                    $returnedXhtml .= " {$parentPage->getNameOrDefault()}</a>";
468*04fd306cSNickeau                                } catch (ExceptionCompile $e) {
469*04fd306cSNickeau                                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the default parent. Error: {$e->getMessage()}");
470*04fd306cSNickeau                                }
471*04fd306cSNickeau                            }
472*04fd306cSNickeau                            /**
473*04fd306cSNickeau                             * End parent tag
474*04fd306cSNickeau                             */
475*04fd306cSNickeau                            $returnedXhtml .= "</li>";
476*04fd306cSNickeau                        }
477*04fd306cSNickeau                    } catch (ExceptionNotFound $e) {
478*04fd306cSNickeau                        // no parent page
479*04fd306cSNickeau                    }
480*04fd306cSNickeau
481*04fd306cSNickeau                }
482*04fd306cSNickeau
483*04fd306cSNickeau                /**
484*04fd306cSNickeau                 * Children (Namespaces/Pages)
485*04fd306cSNickeau                 */
486*04fd306cSNickeau
487*04fd306cSNickeau                $namespaceEnterTag = TagAttributes::createFromCallStackArray($data[PageExplorerTag::NAMESPACE_ATTRIBUTES])
488*04fd306cSNickeau                    ->addClassName($classItem)
489*04fd306cSNickeau                    ->setLogicalTag(PageExplorerTag::CANONICAL . "-{$pageExplorerType}-namespace")
490*04fd306cSNickeau                    ->toHtmlEnterTag("li");
491*04fd306cSNickeau                $pageEnterTag = TagAttributes::createFromCallStackArray($data[PageExplorerTag::PAGE_ATTRIBUTES])
492*04fd306cSNickeau                    ->addClassName($classItem)
493*04fd306cSNickeau                    ->setLogicalTag(PageExplorerTag::CANONICAL . "-{$pageExplorerType}-page")
494*04fd306cSNickeau                    ->toHtmlEnterTag("li");
495*04fd306cSNickeau
496*04fd306cSNickeau
497*04fd306cSNickeau                $pageInstructions = $data[PageExplorerTag::PAGE_INSTRUCTIONS];
498*04fd306cSNickeau                $pageAttributes = $data[PageExplorerTag::PAGE_ATTRIBUTES];
499*04fd306cSNickeau                $namespaceInstructions = $data[PageExplorerTag::NAMESPACE_INSTRUCTIONS];
500*04fd306cSNickeau                $namespaceAttributes = $data[PageExplorerTag::NAMESPACE_ATTRIBUTES];
501*04fd306cSNickeau
502*04fd306cSNickeau                $pageNum = 0;
503*04fd306cSNickeau                foreach (FileSystems::getChildrenContainer($namespacePath) as $subNamespacePath) {
504*04fd306cSNickeau
505*04fd306cSNickeau                    // Namespace
506*04fd306cSNickeau                    if (!($namespaceInstructions === null && $namespaceAttributes !== null)) {
507*04fd306cSNickeau                        try {
508*04fd306cSNickeau                            $subNamespacePage = MarkupPath::getIndexPageFromNamespace($subNamespacePath->toAbsoluteId());
509*04fd306cSNickeau                        } catch (ExceptionBadSyntax $e) {
510*04fd306cSNickeau                            LogUtility::msg("Bad syntax for the namespace $namespacePath. Error: {$e->getMessage()}", LogUtility::LVL_MSG_ERROR, PageExplorerTag::CANONICAL);
511*04fd306cSNickeau                            return false;
512*04fd306cSNickeau                        }
513*04fd306cSNickeau                        if ($subNamespacePage->isHidden()) {
514*04fd306cSNickeau                            continue;
515*04fd306cSNickeau                        }
516*04fd306cSNickeau                        if ($subNamespacePage->exists()) {
517*04fd306cSNickeau                            /**
518*04fd306cSNickeau                             * SubNamespace Enter tag
519*04fd306cSNickeau                             */
520*04fd306cSNickeau                            $returnedXhtml .= $namespaceEnterTag;
521*04fd306cSNickeau
522*04fd306cSNickeau                            /**
523*04fd306cSNickeau                             * SubNamespace Content
524*04fd306cSNickeau                             */
525*04fd306cSNickeau                            if ($namespaceInstructions !== null) {
526*04fd306cSNickeau                                try {
527*04fd306cSNickeau                                    $returnedXhtml .= MarkupRenderUtility::renderInstructionsToXhtml($namespaceInstructions, $subNamespacePage->getMetadataForRendering());
528*04fd306cSNickeau                                } catch (ExceptionCompile $e) {
529*04fd306cSNickeau                                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the sub-namespace. Error: {$e->getMessage()}");
530*04fd306cSNickeau                                }
531*04fd306cSNickeau                            } else {
532*04fd306cSNickeau                                try {
533*04fd306cSNickeau                                    $returnedXhtml .= LinkMarkup::createFromPageIdOrPath($subNamespacePage->getWikiId())
534*04fd306cSNickeau                                        ->toAttributes()
535*04fd306cSNickeau                                        ->toHtmlEnterTag("a");
536*04fd306cSNickeau                                    $returnedXhtml .= Icon::createFromComboResource(PageExplorerTag::FOLDER_ICON)
537*04fd306cSNickeau                                        ->toHtml();
538*04fd306cSNickeau                                    $returnedXhtml .= " {$subNamespacePage->getNameOrDefault()}</a>";
539*04fd306cSNickeau                                } catch (ExceptionCompile $e) {
540*04fd306cSNickeau                                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the default namespace. Error: {$e->getMessage()}");
541*04fd306cSNickeau                                }
542*04fd306cSNickeau
543*04fd306cSNickeau                            }
544*04fd306cSNickeau                            /**
545*04fd306cSNickeau                             * SubNamespace Exit tag
546*04fd306cSNickeau                             */
547*04fd306cSNickeau                            $returnedXhtml .= "</li>";
548*04fd306cSNickeau                        }
549*04fd306cSNickeau
550*04fd306cSNickeau                    }
551*04fd306cSNickeau
552*04fd306cSNickeau                }
553*04fd306cSNickeau
554*04fd306cSNickeau                $childrenLeaf = FileSystems::getChildrenLeaf($namespacePath);
555*04fd306cSNickeau                foreach ($childrenLeaf as $childPagePath) {
556*04fd306cSNickeau                    $childPage = MarkupPath::createPageFromPathObject($childPagePath);
557*04fd306cSNickeau                    if ($childPage->isHidden()) {
558*04fd306cSNickeau                        continue;
559*04fd306cSNickeau                    }
560*04fd306cSNickeau                    if (!($pageInstructions === null && $pageAttributes !== null)) {
561*04fd306cSNickeau                        $pageNum++;
562*04fd306cSNickeau                        if ($currentIndexPage !== null
563*04fd306cSNickeau                            && $childPagePath->getWikiId() !== $currentIndexPage->getWikiId()
564*04fd306cSNickeau                            && FileSystems::exists($childPagePath)
565*04fd306cSNickeau                        ) {
566*04fd306cSNickeau                            /**
567*04fd306cSNickeau                             * Page Enter tag
568*04fd306cSNickeau                             */
569*04fd306cSNickeau                            $returnedXhtml .= $pageEnterTag;
570*04fd306cSNickeau                            /**
571*04fd306cSNickeau                             * Page Content
572*04fd306cSNickeau                             */
573*04fd306cSNickeau                            if ($pageInstructions !== null) {
574*04fd306cSNickeau
575*04fd306cSNickeau                                try {
576*04fd306cSNickeau                                    $returnedXhtml .= MarkupRenderUtility::renderInstructionsToXhtmlFromPage($pageInstructions, $childPage);
577*04fd306cSNickeau                                } catch (ExceptionCompile $e) {
578*04fd306cSNickeau                                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the page. Error: {$e->getMessage()}");
579*04fd306cSNickeau                                }
580*04fd306cSNickeau                            } else {
581*04fd306cSNickeau                                try {
582*04fd306cSNickeau                                    $returnedXhtml .= LinkMarkup::createFromPageIdOrPath($childPagePath->getWikiId())
583*04fd306cSNickeau                                        ->toAttributes()
584*04fd306cSNickeau                                        ->toHtmlEnterTag("a");
585*04fd306cSNickeau                                    $returnedXhtml .= "{$childPage->getNameOrDefault()}</a>";
586*04fd306cSNickeau                                } catch (ExceptionCompile $e) {
587*04fd306cSNickeau                                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the default page. Error: {$e->getMessage()}");
588*04fd306cSNickeau                                }
589*04fd306cSNickeau                            }
590*04fd306cSNickeau                            /**
591*04fd306cSNickeau                             * Page Exit tag
592*04fd306cSNickeau                             */
593*04fd306cSNickeau                            $returnedXhtml .= "</li>";
594*04fd306cSNickeau                        }
595*04fd306cSNickeau                    }
596*04fd306cSNickeau                }
597*04fd306cSNickeau
598*04fd306cSNickeau
599*04fd306cSNickeau                /**
600*04fd306cSNickeau                 * End container tag
601*04fd306cSNickeau                 */
602*04fd306cSNickeau                $returnedXhtml .= "</ul>";
603*04fd306cSNickeau                return $returnedXhtml;
604*04fd306cSNickeau
605*04fd306cSNickeau            case PageExplorerTag::TYPE_TREE:
606*04fd306cSNickeau
607*04fd306cSNickeau                /**
608*04fd306cSNickeau                 * Printing the tree
609*04fd306cSNickeau                 *
610*04fd306cSNickeau                 * data-wiki-id, needed for the
611*04fd306cSNickeau                 * javascript that open the tree
612*04fd306cSNickeau                 * to the actual page
613*04fd306cSNickeau                 */
614*04fd306cSNickeau                $namespaceId = $namespacePath->getWikiId();
615*04fd306cSNickeau                if (!blank($namespaceId)) {
616*04fd306cSNickeau                    $pageExplorerTagAttributes->addOutputAttributeValue("data-" . TagAttributes::WIKI_ID, $namespaceId);
617*04fd306cSNickeau                } else {
618*04fd306cSNickeau                    $pageExplorerTagAttributes->addBooleanOutputAttributeValue("data-" . TagAttributes::WIKI_ID);
619*04fd306cSNickeau                }
620*04fd306cSNickeau
621*04fd306cSNickeau
622*04fd306cSNickeau                $snippetId = PageExplorerTag::CANONICAL . "-" . $pageExplorerType;
623*04fd306cSNickeau                /**
624*04fd306cSNickeau                 * Open the tree until the current page
625*04fd306cSNickeau                 * and make it active
626*04fd306cSNickeau                 */
627*04fd306cSNickeau                PluginUtility::getSnippetManager()->attachJavascriptFromComponentId($snippetId);
628*04fd306cSNickeau                /**
629*04fd306cSNickeau                 * Styling
630*04fd306cSNickeau                 */
631*04fd306cSNickeau                PluginUtility::getSnippetManager()->attachCssInternalStyleSheet($snippetId);
632*04fd306cSNickeau                $returnedXhtml .= $pageExplorerTagAttributes->toHtmlEnterTag("nav") . DOKU_LF;
633*04fd306cSNickeau                $returnedXhtml .= "<ul>" . DOKU_LF;
634*04fd306cSNickeau
635*04fd306cSNickeau                try {
636*04fd306cSNickeau                    $tree = PathTreeNode::buildTreeViaFileSystemChildren($namespacePath);
637*04fd306cSNickeau                    self::treeProcessTree($returnedXhtml, $tree, $data);
638*04fd306cSNickeau                } catch (ExceptionBadSyntax $e) {
639*04fd306cSNickeau                    $returnedXhtml .= LogUtility::wrapInRedForHtml("Error while rendering the tree sub-namespace. Error: {$e->getMessage()}");
640*04fd306cSNickeau                }
641*04fd306cSNickeau
642*04fd306cSNickeau                $returnedXhtml .= "</ul>";
643*04fd306cSNickeau                $returnedXhtml .= "</nav>";
644*04fd306cSNickeau                return $returnedXhtml;
645*04fd306cSNickeau
646*04fd306cSNickeau        }
647*04fd306cSNickeau    }
648*04fd306cSNickeau
649*04fd306cSNickeau    /**
650*04fd306cSNickeau     * Process the
651*04fd306cSNickeau     * @param string $html - the callstack
652*04fd306cSNickeau     * @param PathTreeNode $pathTreeNode
653*04fd306cSNickeau     * @param array $data - the data array from the handler
654*04fd306cSNickeau     * @throws ExceptionBadSyntax
655*04fd306cSNickeau     */
656*04fd306cSNickeau    public static
657*04fd306cSNickeau    function treeProcessTree(string &$html, PathTreeNode $pathTreeNode, array $data)
658*04fd306cSNickeau    {
659*04fd306cSNickeau
660*04fd306cSNickeau        /**
661*04fd306cSNickeau         * Home Page first
662*04fd306cSNickeau         * @var MarkupPath $homePage
663*04fd306cSNickeau         */
664*04fd306cSNickeau        $homePage = null;
665*04fd306cSNickeau        /**
666*04fd306cSNickeau         * @var TreeNode[] $containerTreeNodes
667*04fd306cSNickeau         */
668*04fd306cSNickeau        $containerTreeNodes = [];
669*04fd306cSNickeau        /**
670*04fd306cSNickeau         * @var MarkupPath[] $nonHomePages
671*04fd306cSNickeau         */
672*04fd306cSNickeau        $nonHomePages = [];
673*04fd306cSNickeau
674*04fd306cSNickeau        /**
675*04fd306cSNickeau         * Scanning the tree node to
676*04fd306cSNickeau         * categorize the children as home, page or namespace (container)
677*04fd306cSNickeau         * @var PathTreeNode[] $children
678*04fd306cSNickeau         */
679*04fd306cSNickeau        $children = $pathTreeNode->getChildren();
680*04fd306cSNickeau        foreach ($children as $child) {
681*04fd306cSNickeau
682*04fd306cSNickeau            /**
683*04fd306cSNickeau             * Namespace
684*04fd306cSNickeau             */
685*04fd306cSNickeau            if ($child->hasChildren()) {
686*04fd306cSNickeau
687*04fd306cSNickeau                $containerTreeNodes[] = $child;
688*04fd306cSNickeau
689*04fd306cSNickeau            } else {
690*04fd306cSNickeau                /**
691*04fd306cSNickeau                 * Page
692*04fd306cSNickeau                 */
693*04fd306cSNickeau                $page = MarkupPath::createPageFromPathObject($child->getPath());
694*04fd306cSNickeau                if ($page->isIndexPage()) {
695*04fd306cSNickeau                    $homePage = $page;
696*04fd306cSNickeau                } else {
697*04fd306cSNickeau                    $nonHomePages[] = $page;
698*04fd306cSNickeau                }
699*04fd306cSNickeau
700*04fd306cSNickeau            }
701*04fd306cSNickeau
702*04fd306cSNickeau        }
703*04fd306cSNickeau
704*04fd306cSNickeau        /**
705*04fd306cSNickeau         * First the home page
706*04fd306cSNickeau         */
707*04fd306cSNickeau        if ($homePage !== null) {
708*04fd306cSNickeau            PageExplorerTag::treeProcessLeaf($html, $homePage, $data, PageExplorerTag::HOME_TYPE);
709*04fd306cSNickeau        }
710*04fd306cSNickeau
711*04fd306cSNickeau        /**
712*04fd306cSNickeau         * The subdirectories
713*04fd306cSNickeau         */
714*04fd306cSNickeau        $namespaceInstructions = $data[PageExplorerTag::NAMESPACE_INSTRUCTIONS];
715*04fd306cSNickeau        foreach ($containerTreeNodes as $containerTreeNode) {
716*04fd306cSNickeau
717*04fd306cSNickeau            /**
718*04fd306cSNickeau             * @var WikiPath $containerPath
719*04fd306cSNickeau             */
720*04fd306cSNickeau            $containerPath = $containerTreeNode->getPath();
721*04fd306cSNickeau
722*04fd306cSNickeau            /**
723*04fd306cSNickeau             * Entering: Creating in instructions form
724*04fd306cSNickeau             * the same as in markup form
725*04fd306cSNickeau             *
726*04fd306cSNickeau             * <li>
727*04fd306cSNickeau             *    <button data-bs-target="#id" data-bs-collapse="collapse">
728*04fd306cSNickeau             *      Label
729*04fd306cSNickeau             *    </button>
730*04fd306cSNickeau             *    <div id="id">
731*04fd306cSNickeau             *      <ul>
732*04fd306cSNickeau             *        <li></li>
733*04fd306cSNickeau             *        <li></li>
734*04fd306cSNickeau             *        ....
735*04fd306cSNickeau             *    </div>
736*04fd306cSNickeau             *    ...
737*04fd306cSNickeau             */
738*04fd306cSNickeau            $html .= "<li>";
739*04fd306cSNickeau
740*04fd306cSNickeau
741*04fd306cSNickeau            /**
742*04fd306cSNickeau             * Keep the id unique on the page in order to be able to collapse
743*04fd306cSNickeau             * the good HTML node
744*04fd306cSNickeau             */
745*04fd306cSNickeau            $namespaceId = ExecutionContext::getActualOrCreateFromEnv()->getIdManager()->generateNewHtmlIdForComponent("page-explorer-{$containerPath->getWikiId()}");
746*04fd306cSNickeau            $id = StyleAttribute::addComboStrapSuffix($namespaceId);
747*04fd306cSNickeau            $html .= TagAttributes::createEmpty()
748*04fd306cSNickeau                ->addOutputAttributeValue("data-bs-target", "#$id")
749*04fd306cSNickeau                ->addOutputAttributeValue("data-" . TagAttributes::WIKI_ID, $containerPath->getWikiId())
750*04fd306cSNickeau                ->addOutputAttributeValue("data-bs-toggle", "collapse")
751*04fd306cSNickeau                ->addOutputAttributeValue("aria-expanded", "false")
752*04fd306cSNickeau                ->addClassName("btn")
753*04fd306cSNickeau                ->addClassName("align-items-center")
754*04fd306cSNickeau                ->addClassName("rounded")
755*04fd306cSNickeau                ->toHtmlEnterTag("button");
756*04fd306cSNickeau
757*04fd306cSNickeau            // Button label
758*04fd306cSNickeau
759*04fd306cSNickeau            $subHomePage = MarkupPath::getIndexPageFromNamespace($containerPath->toAbsoluteId());
760*04fd306cSNickeau            if ($subHomePage->exists()) {
761*04fd306cSNickeau                if ($namespaceInstructions !== null) {
762*04fd306cSNickeau                    try {
763*04fd306cSNickeau                        $html .= MarkupRenderUtility::renderInstructionsToXhtml($namespaceInstructions, $subHomePage->getMetadataForRendering());
764*04fd306cSNickeau                    } catch (ExceptionCompile $e) {
765*04fd306cSNickeau                        $html .= LogUtility::wrapInRedForHtml("Error while rendering the child directory. Error: {$e->getMessage()}");
766*04fd306cSNickeau                    }
767*04fd306cSNickeau                } else {
768*04fd306cSNickeau                    $html .= $subHomePage->getNameOrDefault();
769*04fd306cSNickeau                }
770*04fd306cSNickeau            } else {
771*04fd306cSNickeau                $namespaceName = PageExplorerTag::toNamespaceName($containerPath);
772*04fd306cSNickeau                $html .= $namespaceName;
773*04fd306cSNickeau            }
774*04fd306cSNickeau            // End button
775*04fd306cSNickeau            $html .= "</button>";
776*04fd306cSNickeau
777*04fd306cSNickeau            /**
778*04fd306cSNickeau             * Sub and Recursion
779*04fd306cSNickeau             */
780*04fd306cSNickeau            $html .= TagAttributes::createEmpty()
781*04fd306cSNickeau                ->addClassName("collapse")
782*04fd306cSNickeau                ->addOutputAttributeValue(TagAttributes::ID_KEY, "$id")
783*04fd306cSNickeau                ->toHtmlEnterTag("div");
784*04fd306cSNickeau            $html .= "<ul>";
785*04fd306cSNickeau            self::treeProcessTree($html, $containerTreeNode, $data);
786*04fd306cSNickeau            $html .= "</ul>";
787*04fd306cSNickeau            $html .= "</div>";
788*04fd306cSNickeau
789*04fd306cSNickeau            /**
790*04fd306cSNickeau             * Closing: Creating in instructions form
791*04fd306cSNickeau             * the same as in markup form
792*04fd306cSNickeau             *
793*04fd306cSNickeau             *   </$pageExplorerTreeListTag>
794*04fd306cSNickeau             * </$pageExplorerTreeTag>
795*04fd306cSNickeau             */
796*04fd306cSNickeau            $html .= "</li>";
797*04fd306cSNickeau
798*04fd306cSNickeau        }
799*04fd306cSNickeau
800*04fd306cSNickeau        /**
801*04fd306cSNickeau         * Then the other pages
802*04fd306cSNickeau         */
803*04fd306cSNickeau        foreach ($nonHomePages as $page) {
804*04fd306cSNickeau            PageExplorerTag::treeProcessLeaf($html, $page, $data, PageExplorerTag::PAGE_TYPE);
805*04fd306cSNickeau        }
806*04fd306cSNickeau
807*04fd306cSNickeau
808*04fd306cSNickeau    }
809*04fd306cSNickeau}
810*04fd306cSNickeau
811