Optimierung pages-Tabelle / Tree

Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

Punkt 1: Optimierung pages-Tabelle

Spalte "language" -> derzeit Text (z.B. "DE"), könnte aber auf addons-Tabelle verlinken
Spalte "template" -> desgleichen

Spalte "menu" -> Zur Diskussion: Vielleicht macht es Sinn, für Menüs eine eigene Tabelle mit Einstellungen einzurichten? Dann würde hier die ID des Menüs stehen, also ein Foreign Key. Hätte den netten Nebeneffekt, dass Menüs über eine grafische Oberfläche administrierbar wären und man keine lustigen Aufrufe mit 30 Parametern im Template bräuchte. Nur noch "{showmenu(<ID>)}" und alles andere macht ein Admintool.

Punkt 2: Tree

Baumstrukturen sind immer eine haarige Angelegenheit. Es gibt diverse Algorithmen, angefangen von "Adjacency Lists" - das ist das was wir machen - über Closure Tables zu Nested Sets. Alle haben ihre Vor- und Nachteile und ihre Daseinsberechtigung. Bei allen kriegt man irgendwann einen "Buffer overflow" im Hirn. :lol:

Das Problem ist, dass wir beispielsweise den Seitenbaum nicht nur aus der Datenbank auslesen und darstellen müssen, sondern diverse Eigenschaften damit verbinden. Beispiele:
  • Aktuelle Seite im Menü markieren
  • Alle direkt übergeordneten Seiten der aktuellen Seite markieren ("Ancestors")
  • Nur Seiten auf der gleichen Ebene anzeigen ("Siblings")
  • Nur nachgeordnete Seiten einer Seite anzeigen ("Descestors" oder "Children")
  • Pfad zur Seite anzeigen ("Breadcrumb")
Derzeit wird der Seitenbaum einmal in einem Rutsch aus der Datenbank ausgelesen, um Datenbankzugriffe zu sparen. Dann wird die Liste nachbearbeitet, um z.B. alle Seiten, die zum aktuelle Pfad gehören, zu markieren. Nachteil: Das passiert auch dann, wenn es hinterher gar nicht gebraucht wird.

Meine Überlegung: Aus dem Seitenbaum einen "echten" Baum machen. https://github.com/nicmart/Tree

Eigenschaften wie "isLeaf()" (letztes Element im Pfad), "hasChildren()" (es gibt Unterseiten), "isRoot()" (es ist eine Level-0-Seite) etc. können dann zu dem Zeitpunkt aufgerufen werden, wenn sie wirklich gebraucht werden.
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

So, ich hab mal die Basis-Klasse von "nicmart" genommen und erweitert.

Aus diesem Array...

Code: Alles auswählen

Array
(
    [0] => Array
        (
            [page_id] => 64
            [site_id] => 1
            [vis_id] => 7
            [parent] => 0
            [link] => /Homepage englisch
            [page_title] => Homepage englisch
            [menu_title] => Homepage englisch
            [description] => 
            [template] => 
            [position] => 1
            [menu] => 1
            [language] => EN
            [searching] => 1
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1533224458
            [visibility] => draft
        )

    [1] => Array
        (
            [page_id] => 30
            [site_id] => 1
            [vis_id] => 1
            [parent] => 0
            [link] => /Homepage
            [page_title] => Homepage
            [menu_title] => Homepage
            [description] => 
            [template] => 
            [position] => 2
            [menu] => 1
            [language] => DE
            [searching] => 0
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1531847409
            [visibility] => public
        )

    [2] => Array
        (
            [page_id] => 53
            [site_id] => 1
            [vis_id] => 1
            [parent] => 0
            [link] => /Demo
            [page_title] => Demo
            [menu_title] => Demo
            [description] => 
            [template] => 
            [position] => 3
            [menu] => 1
            [language] => DE
            [searching] => 0
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 0
            [visibility] => public
        )

    [3] => Array
        (
            [page_id] => 59
            [site_id] => 1
            [vis_id] => 1
            [parent] => 53
            [link] => /Demo/Demo 2
            [page_title] => Demo 2
            [menu_title] => Demo 2
            [description] => 
            [template] => 
            [position] => 1
            [menu] => 1
            [language] => DE
            [searching] => 1
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1532617238
            [visibility] => public
        )

    [4] => Array
        (
            [page_id] => 60
            [site_id] => 1
            [vis_id] => 1
            [parent] => 53
            [link] => /Demo/Demo 3
            [page_title] => Demo 3
            [menu_title] => Demo 3
            [description] => 
            [template] => 
            [position] => 2
            [menu] => 1
            [language] => DE
            [searching] => 1
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1532617284
            [visibility] => public
        )

    [5] => Array
        (
            [page_id] => 61
            [site_id] => 1
            [vis_id] => 1
            [parent] => 59
            [link] => /Demo/Demo 2/Demo 4
            [page_title] => Demo 4
            [menu_title] => Demo 4
            [description] => 
            [template] => 
            [position] => 3
            [menu] => 1
            [language] => DE
            [searching] => 1
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1532617334
            [visibility] => public
        )

    [6] => Array
        (
            [page_id] => 62
            [site_id] => 1
            [vis_id] => 7
            [parent] => 60
            [link] => /Demo/Demo 3/Demo 5
            [page_title] => Demo 5
            [menu_title] => Demo 5
            [description] => 
            [template] => 
            [position] => 4
            [menu] => 1
            [language] => DE
            [searching] => 1
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1532617350
            [visibility] => draft
        )

    [7] => Array
        (
            [page_id] => 63
            [site_id] => 1
            [vis_id] => 7
            [parent] => 62
            [link] => /Demo/Demo 3/Demo 5/Demo 6
            [page_title] => Demo 6
            [menu_title] => Demo 6
            [description] => 
            [template] => 
            [position] => 1
            [menu] => 1
            [language] => DE
            [searching] => 1
            [created_by] => 1
            [modified_by] => 1
            [modified_when] => 1532617385
            [visibility] => draft
        )

)
...wird dieser Tree...

Code: Alles auswählen

CAT\Helper\PageNode Object
(
    [link:CAT\Helper\PageNode:private] => 
    [menu:CAT\Helper\PageNode:private] => 
    [menu_id:CAT\Helper\PageNode:private] => 
    [title:CAT\Helper\PageNode:private] => 
    [description:CAT\Helper\PageNode:private] => 
    [visibility:CAT\Helper\PageNode:private] => 
    [value:Tree\Node\Node:private] => __root__
    [parent:Tree\Node\Node:private] => 
    [children:Tree\Node\Node:private] => Array
        (
            [0] => CAT\Helper\PageNode Object
                (
                    [link:CAT\Helper\PageNode:private] => /Homepage englisch
                    [menu:CAT\Helper\PageNode:private] => Homepage englisch
                    [menu_id:CAT\Helper\PageNode:private] => 1
                    [title:CAT\Helper\PageNode:private] => Homepage englisch
                    [description:CAT\Helper\PageNode:private] => 
                    [visibility:CAT\Helper\PageNode:private] => 7
                    [value:Tree\Node\Node:private] => 64
                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                    [children:Tree\Node\Node:private] => Array
                        (
                        )

                )

            [1] => CAT\Helper\PageNode Object
                (
                    [link:CAT\Helper\PageNode:private] => /Homepage
                    [menu:CAT\Helper\PageNode:private] => Homepage
                    [menu_id:CAT\Helper\PageNode:private] => 1
                    [title:CAT\Helper\PageNode:private] => Homepage
                    [description:CAT\Helper\PageNode:private] => 
                    [visibility:CAT\Helper\PageNode:private] => 1
                    [value:Tree\Node\Node:private] => 30
                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                    [children:Tree\Node\Node:private] => Array
                        (
                        )

                )

            [2] => CAT\Helper\PageNode Object
                (
                    [link:CAT\Helper\PageNode:private] => /Demo
                    [menu:CAT\Helper\PageNode:private] => Demo
                    [menu_id:CAT\Helper\PageNode:private] => 1
                    [title:CAT\Helper\PageNode:private] => Demo
                    [description:CAT\Helper\PageNode:private] => 
                    [visibility:CAT\Helper\PageNode:private] => 1
                    [value:Tree\Node\Node:private] => 53
                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                    [children:Tree\Node\Node:private] => Array
                        (
                            [0] => CAT\Helper\PageNode Object
                                (
                                    [link:CAT\Helper\PageNode:private] => /Demo/Demo 2
                                    [menu:CAT\Helper\PageNode:private] => Demo 2
                                    [menu_id:CAT\Helper\PageNode:private] => 1
                                    [title:CAT\Helper\PageNode:private] => Demo 2
                                    [description:CAT\Helper\PageNode:private] => 
                                    [visibility:CAT\Helper\PageNode:private] => 1
                                    [value:Tree\Node\Node:private] => 59
                                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                                    [children:Tree\Node\Node:private] => Array
                                        (
                                            [0] => CAT\Helper\PageNode Object
                                                (
                                                    [link:CAT\Helper\PageNode:private] => /Demo/Demo 2/Demo 4
                                                    [menu:CAT\Helper\PageNode:private] => Demo 4
                                                    [menu_id:CAT\Helper\PageNode:private] => 1
                                                    [title:CAT\Helper\PageNode:private] => Demo 4
                                                    [description:CAT\Helper\PageNode:private] => 
                                                    [visibility:CAT\Helper\PageNode:private] => 1
                                                    [value:Tree\Node\Node:private] => 61
                                                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                                                    [children:Tree\Node\Node:private] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [1] => CAT\Helper\PageNode Object
                                (
                                    [link:CAT\Helper\PageNode:private] => /Demo/Demo 3
                                    [menu:CAT\Helper\PageNode:private] => Demo 3
                                    [menu_id:CAT\Helper\PageNode:private] => 1
                                    [title:CAT\Helper\PageNode:private] => Demo 3
                                    [description:CAT\Helper\PageNode:private] => 
                                    [visibility:CAT\Helper\PageNode:private] => 1
                                    [value:Tree\Node\Node:private] => 60
                                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                                    [children:Tree\Node\Node:private] => Array
                                        (
                                            [0] => CAT\Helper\PageNode Object
                                                (
                                                    [link:CAT\Helper\PageNode:private] => /Demo/Demo 3/Demo 5
                                                    [menu:CAT\Helper\PageNode:private] => Demo 5
                                                    [menu_id:CAT\Helper\PageNode:private] => 1
                                                    [title:CAT\Helper\PageNode:private] => Demo 5
                                                    [description:CAT\Helper\PageNode:private] => 
                                                    [visibility:CAT\Helper\PageNode:private] => 7
                                                    [value:Tree\Node\Node:private] => 62
                                                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                                                    [children:Tree\Node\Node:private] => Array
                                                        (
                                                            [0] => CAT\Helper\PageNode Object
                                                                (
                                                                    [link:CAT\Helper\PageNode:private] => /Demo/Demo 3/Demo 5/Demo 6
                                                                    [menu:CAT\Helper\PageNode:private] => Demo 6
                                                                    [menu_id:CAT\Helper\PageNode:private] => 1
                                                                    [title:CAT\Helper\PageNode:private] => Demo 6
                                                                    [description:CAT\Helper\PageNode:private] => 
                                                                    [visibility:CAT\Helper\PageNode:private] => 7
                                                                    [value:Tree\Node\Node:private] => 63
                                                                    [parent:Tree\Node\Node:private] => CAT\Helper\PageNode Object
 *RECURSION*
                                                                    [children:Tree\Node\Node:private] => Array
                                                                        (
                                                                        )
                                                                )
                                                        )
                                                )
                                        )
                                )
                        )
                )
        )
)
Jetzt müßte es eigentlich möglich sein, einen Visitor zu bauen, der das gewünschte Menü generiert...
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

So, nach etlichem Gebastel und Probieren hab ich es endlich hingekriegt, dass ich zumindest schon mal den Seitenbaum vollständig und mit korrekter Einrückung darstellen kann. *seufz*

Ich mußte dazu einen eigenen Iterator implementieren:

Code: Alles auswählen

    class listNodeIterator extends \RecursiveArrayIterator
    {

        private $tree;

        public function __construct($tree)
        {
           $this->tree = $tree;
        }

        public function next()
        {
           next($this->tree);
           return;
        }

        public function current()
        {
           return current($this->tree);
        }

        public function rewind()
        {
           reset($this->tree);
           return;
        }

        public function key()
        {
           return key($this->tree);
        }

        public function valid()
        {
            return (isset($this->tree[key($this->tree)]) && is_object($this->tree[key($this->tree)]) && $this->tree[key($this->tree)] instanceof ListNode);
        }

        public function getChildren()
        {
            return new listNodeIterator($this->current()->getChildren());
        }
        public function hasChildren()
        {
            return ( count($this->tree[key($this->tree)]->getChildren()) > 0 );
        }
    }
Dann kommt mit diesem Code:

Code: Alles auswählen

foreach (new \RecursiveIteratorIterator(new \wblib\wbList\listNodeIterator($children), \RecursiveIteratorIterator::SELF_FIRST) as $key => $val)
{
    echo str_repeat("|- ",$val->getDepth()), $val->getValue(), "<br />";
}
...das hier raus:

|- Demo
|- |- Demo 2
|- |- |- Demo 4
|- |- Demo 3
|- |- |- Demo 5
|- |- |- |- Demo 6
|- Homepage
|- Homepage englisch
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

Nuja...

Code: Alles auswählen

        <ul id="" class="tree">
            <li id="" class="item first has-child">Demo
                <ul id="" class="tree">
                    <li id="" class="item first has-child">Demo 2
                        <ul id="" class="tree">
                            <li id="" class="item first last">Demo 4</li>
                        </ul>
                    </li>
                    <li id="" class="item last has-child">Demo 3
                        <ul id="" class="tree">
                            <li id="" class="item first last has-child">Demo 5
                                <ul id="" class="tree">
                                    <li id="" class="item first last">Demo 6</li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li id="" class="item">Homepage</li>
            <li id="" class="item last">Homepage englisch</li>
        </ul>
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
creativecat
Beiträge: 1430
Registriert: Mi 6. Feb 2013, 12:41
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von creativecat »

shadowcat hat geschrieben:
Fr 10. Aug 2018, 14:40
Ich mußte dazu einen eigenen Iterator implementieren:

Code: Alles auswählen

    class listNodeIterator extends \RecursiveArrayIterator
    {

        private $tree;

        public function __construct($tree)
        {
           $this->tree = $tree;
        }

        public function next()
        {
           next($this->tree);
           return;
        }

        public function current()
        {
           return current($this->tree);
        }

        public function rewind()
        {
           reset($this->tree);
           return;
        }

        public function key()
        {
           return key($this->tree);
        }

        public function valid()
        {
            return (isset($this->tree[key($this->tree)]) && is_object($this->tree[key($this->tree)]) && $this->tree[key($this->tree)] instanceof ListNode);
        }

        public function getChildren()
        {
            return new listNodeIterator($this->current()->getChildren());
        }
        public function hasChildren()
        {
            return ( count($this->tree[key($this->tree)]->getChildren()) > 0 );
        }
    }
Immer wieder erschreckend begeisternd. In so wenig Code, steckt so viel Hirnschmalz und er kann so viel...
:daumen:
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

Ja, nur bis ich so weit war...

Ich hab mir am Samstag ein Schaufelblatt über den Schädel gezogen, vielleicht kann ich jetzt besser denken.
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

Ich brauch mal etwas fremdes Gehirn. :lol: Ich hole mal eben aus:

Der neue ListBuilder basiert ja auf dem Baum und dem Iterator. Für die Darstellung gibt es Views, Formatter genannt, und die wiederum bestehen letztendlich aus einem Haufen Templates und ein bißchen Logik. So kann man z.B. einen eigenen Formatter für eine komplette <ul>-Liste haben und diesem dann sagen "mach mal ein Bootstrap-Menü da draus". So weit so gut.

Jetzt hat der Formatter schon einen ganzen Haufen Optionen, die man setzen kann:

Code: Alles auswählen

            // ***** template *****
            'template_dir'          => null,
            'template_type'         => 'bootstrap',
            'template_variant'      => 'navbar',
            // ***** menu options *****
            'min_level'             => 0,
            'max_level'             => -1,
            // ***** css options *****
            'outer_list_class'      => 'navbar-nav mr-auto',
            'inner_list_class'      => '',
            'li_class'              => 'item',
            'first_li_class'        => 'first',
            'last_li_class'         => 'last',
            'trail_li_class'        => 'trail',
            'current_li_class'      => 'current',
            'has_child_li_class'    => 'has-children',
            'link_class'            => '',
            'first_link_class'      => '',
            'last_link_class'       => '',
            'trail_link_class'      => '',
            'has_child_link_class'  => '',
            'current_link_class'    => '',
Aus template_dir, type und variant wird ein Pfad zusammengesetzt, also z.B. <Basis>/bootstrap/navbar. Es entsteht quasi eine Default-Bootstrap-Navbar. Die Level sollten auch klar sein, man muß ja nicht immer mit Level 1 = Root anfangen und nicht immer das komplette Menü anzeigen, was aber der Default ist.

Jetzt kommen wir aber zu den ganzen CSS-Klassen. Ich nehme als Beispiel das Template bs_business, und da gibt es einen Workaround um das Problem, daß Bootstrap standardmäßig in der Navbar nur 2 Ebenen kann. Hierfür bräuchte nicht nur der erste ul-Level eine eigene CSS-Klasse, sondern auch der 2. und der 3. Aber man kann ja nicht für X Ebenen solche Schlüssel vorsehen.

Ich dachte jetzt schon an ein Array, also sowas wie

'list_classes' => array(1 => 'rootlevel', 2 => 'erstersublevel', 3 => 'zweitersublevel') // usw

Ich bin mir nur nicht sicher, wie "einprägsam" das wohl ist...

Hier übrigens der aktuelle Code aus der Menu.php für das Erzeugen eines Fullmenüs:

Code: Alles auswählen

        public static function fullMenu($menu_number=NULL,array &$options = array())
        {
            self::log()->addDebug('fullMenu - menu number [{num}]',array('num'=>$menu_number));
            $pid  = NULL;
            self::checkPageId($pid);
            self::checkOptions($options);
            self::log()->addDebug('current page [{pid}] options [{opt}]',array('pid'=>$pid,'opt'=>print_r($options,1)));
            $menu = $menu_number
                  ? \CAT\Helper\Page::getPagesForMenu($menu_number)
                  : \CAT\Helper\Page::getPages()
                  ;
            $renderer = new \wblib\wbList\Formatter\ListFormatter($options);
            $renderer->setCurrent($pid);
            return $renderer->render(self::tree());
        }   // end function fullMenu()
Das erzeugte Menü sieht so weit schon fast okay aus, abgesehen von dem besagten 3. Level. Das ist im Screenshot nicht offensichtlich, aber die Verschachtelung ist etwas anders.
Dateianhänge
2018-08-14 14_41_46-BlackCat CMS Backend _ Dashboard.png
2018-08-14 14_41_46-BlackCat CMS Backend _ Dashboard.png (3.8 KiB) 4437 mal betrachtet
2018-08-14 14_40_35-Homepage.png
2018-08-14 14_40_35-Homepage.png (7.92 KiB) 4437 mal betrachtet
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

Menü händisch repariert, so wäre es richtig. Dazu muß ab der 3. Ebene die Klasse "sub-menu" beim <ul> hinzugefügt werden.
Dateianhänge
2018-08-14 14_45_38-Homepage.png
2018-08-14 14_45_38-Homepage.png (6.49 KiB) 4435 mal betrachtet
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

So, ein neues Update. Erst mal zum ListFormatter:

Code: Alles auswählen

protected static $defaults = array(
            // ***** template *****
            'template_dir'          => null,
            'template_type'         => 'bootstrap',
            'template_variant'      => 'navbar',
            // ***** css classes *****
            'ul'                    => array(
                'first'      => null,
                'last'       => null,
                'child'      => 'dropdown',
                'current'    => 'active',
                'trail'      => 'active',
            ),
            'li'                    => array(
                'first'      => null,
                'last'       => null,
                'child'      => 'dropdown',
                'current'    => 'active',
                'trail'      => 'active',
            ),
        );
Das ist noch nicht der letzte Wurf, und die Defaults beziehen sich im Moment auf eine Bootstrap NavBar.

Ich hab mich jetzt doch entschieden, einen "Menu Manager" als Admin-Tool zu bauen. Ich hatte vor Jahren schon mal ein Modul für Websitebaker gebaut, die Entwicklung aber wieder eingestellt. (Damals waren die SM2 Verfechter sehr stark vertreten.) Das Praktische ist: Man muß sich keine Parameter merken, nur noch das Markup {menu(<Nummer>)} in Template und der Rest geht per GUI.
2018-08-15 11_08_05-BlackCat CMS Backend _ Admin Werkzeuge.png
2018-08-15 11_08_05-BlackCat CMS Backend _ Admin Werkzeuge.png (19.66 KiB) 4427 mal betrachtet
Die Optionen sind naturgemäß sehr stark an den neuen ListBuilder angelehnt, sollen aber so flexibel wie möglich sein. Daher möchte ich mal Euren Blick auf folgende Einstellungen richten:

1:nav nav-pills ddmenu
2:dropdown-menu
>=3:dropdown-menu sub-menu

Daß Menüs in der Regel verschachtelte Listen (<ul> oder <ol>) sind, dürfte allgemein bekannt sein. Bootstrap unterstützt out-of-the-box aber nur Menüs mit maximal zwei Ebenen. Es gibt diverse Snippets, um das zu lösen, und in meinem konkreten Beispiel ist es folgendermaßen:
  • Der ganz äußere <ul> hat die Klassen "nav nav-pills ddmenu", wobei die ersten beiden Bootstrap-Klassen sind und die dritte zur Lösung gehört.
  • <ul> auf der ersten untergeordneten Ebene haben die Klasse "dropdown-menu".
  • Jede weitere Ebene darunter hat die Klassen "dropdown-menu sub-menu".
Damit man nun nicht für X Ebenen immer und immer wieder die Klassen angeben muß (man weiß ja auch nicht unbedingt von Anfang an, wie viele Ebenen man haben wird), habe ich mir die Angaben ">", "<", ">=" und "<=" überlegt. Äußerst kreativ, ich weiß. :mrgreen: Somit "weiß" jetzt der ListBuilder für jede Ebene, welche Klassen er zu verwenden hat.

Das gleiche natürlich analog auch für die <li> und <a> im Menü.

Kommen wir zurück zum ListFormatter von ganz oben. Mit Hilfe der Funktionen setLevelClasses() und setClasses() kann man nun zum einen diese Level-basierten CSS-Klassen übergeben, als auch die Standardklassen für "Einträge mit Untereinträgen" ("child"), "aktuelle Seite" (current), usw. Das wiederum erledigt unsere Menu Helper Klasse, die dazu die Menünummer aus dem {menu()} Markup nimmt und die dazugehörigen Einstellungen aus der Datenbank zieht. Dazu gehört dann z.B. auch der Menütyp, also z.B. "Fullmenu" oder "Breadcrumb".

Kurzum, von all den Details hier muß der normale Administrator gar nichts wissen, er braucht nur die Menünummer und "fertig ist die Laube". :mrgreen:

Vielleicht kriege ich sogar noch einen "Menu Analyzer" hin, dem man ein Markup vorwirft (z.B. einen Ausschnitt aus einem Bootstrap Snippet) und der daraufhin die Optionen - im wesentlichen die CSS-Klassen - ermittelt. Das wird nicht so weit gehen (können), daß der auch noch das HTML-Markup im Detail analysiert, aber was die CSS-Klassen angeht, bin ich da eigentlich recht zuversichtlich.
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Benutzeravatar
shadowcat
Administrator
Beiträge: 5283
Registriert: Di 5. Feb 2013, 10:36
Kontaktdaten:

Re: Optimierung pages-Tabelle / Tree

Beitrag von shadowcat »

Achso, natürlich wird es dann auch noch die Möglichkeit geben, CSS und JS an das Menü zu hängen, das dann mit {get_page_headers()} und {get_page_footers()} automatisch geladen wird...
My software never has bugs, it just develops random features.
If it’s not broken, keep fixing it until it is
Antworten