The PHP Layers Menu
A Horizontal Menu Structure File and the Source Code for this Demo

A vertical menu... and its
Menu Structure File

Tree - No JavaScript

|  | Linus B. Torvalds
|  | Linux Kernel Archives
|  | Linux Distributions

Plain - No JavaScript

Another vertical menu...

Tree - No JavaScript

|  | Linux related sites
|  | DOM, layers...

Another horizontal menu... and its Menu Structure File

Horizontal Plain version - No JavaScript

    -------------------------
    The PHP Layers Menu 2.2.0
    -------------------------

    It is released under the GNU Lesser General Public License,
    either Version 2.1, or (at your option) any later version
    (see the file COPYING for details).

    It is a hierarchical dynamic menu system to rapidly choose
    among the items.
    It achieves a compact view and a reasonably small file size
    for the page also with a very large number of entries.
    An arbitrary number of vertical and horizontal menus can be used
    on the same page.
    The menus behaviour is analogous to the Gnome, KDE, and MS Windows
    main menus.
    You can use as much levels as you need and the menu is dynamically
    generated starting from the menu structure (that is read from a file
    or from a string), that is rather simple and intuitive.
    An extended class is provided to prepare also Tree Menus (that
    are analogous to the most widely used file managers, but require
    the PHP support on the server) and Plain Menus that do not require
    JavaScript to work.
    It is easy to use, as you can see looking at the demo menu structures
    and at the demo script source code.

    It works with both PHP3 and PHP4; it employs the Template class
    of PHPLib.
    If you want to try it without PHP installed, load in your browser
    the static demo, i.e. index-static.html (please note that, in this
    case, tree menus do not expand and their contents are static).

    The PHP Layers Menu uses JavaScript; it has been tested
    and it works at least with the following browsers:

    - Mozilla >= 0.6 (version >= 0.9.1 is suggested)
    - Netscape >= 6.0 and other browsers based on Mozilla, e.g. Galeon
    - Netscape >= 4.07
    - Konqueror >= 2.1 (see in the following)
    - Opera 5 and 6
    - Internet Explorer 4, 5, 5.5, 6

    Some notes about Konqueror...
    All the layers should disappear when clicking elsewhere
    in the browser window; this works on Konqueror >= 2.2,
    but it does not work on Konqueror 2.1.
    The layers menu is not correctly usable with Konqueror 1.9.8 (KDE 2.0),
    because K. 1.9.8 triggers onmouseover events also for hidden layers;
    currently, I do not know if there is a way to avoid this behaviour.

    Browser detection
    -----------------

    Basically, the following cases are considered:
    DOM --> Document Object Model ( http://www.w3c.org/DOM/ )
    NS4 --> Netscape 4.x
    IE4 --> Internet Explorer 4

    Apart from some details and workarounds, it is made the simplifying
    assumption that sufficiently recent browsers (Mozilla >= 0.6,
    NS >= 6.0, Konqueror >= 2.1, Opera 5 and 6, IE >= 5) can be considered
    compliant to the DOM specifications if only not-so-much-advanced
    features are employed, while Netscape 4.x and Internet Explorer 4
    have to be handled as distinct cases.
    Here and there it is necessary to use specific code also for
    Konqueror, Opera, and Internet Explorer.

    Working principle
    -----------------

    The generation of layers is based on a depth-first search over the tree,
    as it can be easily understood examining layersmenu*.txt.
    The depth-first search allows to logically arrange in a one-dimension
    sequence the tree's nodes, just as the directories in file managers
    providing a tree view (for example, the Gnome's "gmc" and Nautilus,
    and the MS Windows' file browser) when all branches are expanded,
    to show all subdirectories.

    Nodes-layers correspondence
    ---------------------------

    In the categories tree, the "root node" is represented
    by the "Top" category, that does not appear in the layers menu.
    Then we have to consider the children of the root node,
    i.e. the "first-level" subcategories (of "Top"), that have to be
    handled differently from the other nodes, as they have to be always
    visible on the page.
    Finally, we have to distinguish leaf nodes - i.e. the ones without
    children - (categories without corresponding subcategories) from
    all the other nodes; such distinction is significant also for
    the children of the root node ("first-level" subcategories);
    in the subsequent part of the present document it will be clear why
    leaf nodes have to be handled a bit differently from the other nodes.

    Layers Menu and Tree Menu, the underlying algorithm
    ---------------------------------------------------

    The algorithm employed to generate the needed layers performs a scan
    of nodes analogous to the one foreseen in the PHP Tree Menu 1.1,
    authored by Bjorge Dijkstra (bjorge@gmx.net) and published at
    http://www.zinc.f2s.com/scriptorium/index.php/treemenu
    In fact, the Layers Menu scans the nodes reading a menu structure
    whose format is analogous to the one used by the PHP Tree Menu 1.1.

    Implementation driving rules
    ----------------------------

    Each layer lists all the children of a not-leaf node; each
    of these children has a link to the corresponding URL associated with.

    The root node's children (i.e. the subcategories of "Top")
    can be considered as belonging to a "special" layer, as they have
    to be always visible on the page, while, in the general case,
    all other layers are hidden.

    Each layer is defined when it is involved by the depth-first search;
    its geometrical placement is identified by its top-left corner
    coordinates and it depends by the route leading to it.
    In particular, it depends on the position and width of the
    "father" layer and on size and scroll of the browsing window;
    the vertical coordinate has to be related to the vertical coordinate
    of the link corresponding to the "father node".

    A popUpL([layername]) function is defined, that is used to set as visible
    the layer labeled as [layername]; for a given layer, the label (name)
    is obtained as 'L[N]', where [N] is a progressive integer number,
    identifying the position (line) of the father node inside
    the depth-first search result (starting from 0 for the root node).

    A shutdown() function is defined, that is used to set as hidden
    all the layers (only links related the root node's children
    are always visible on the page).

    A popUp([menuName]) function is defined, that is used to set as visible
    all layers corresponding to the route leading to the corresponding layer,
    starting from the link related to a root node's child.
    All other layers have to be hidden, hence such a function starts calling
    the shutdown() and the set as visible all the layers on the name route.

    It is imposed that the Layers Menu behaviour is completely analogous
    to the behaviour of the Gnome and KDE main menus and of the "Start" menu
    of MS Windows.
    This last rule implies the following sub rules.

    	In any case, a click event outside of visible layers
    	has to trigger the hiding of all the layers (shutdown()).

    	The positioning of the mouse pointer over a link corresponding
    	to a non-leaf node has to trigger the visibility of all the
    	layers on the route to the layer containing the "children
    	of the link", and only of that layers, while all the others
    	have to be hidden.

    	The positioning of the mouse pointer over a link corresponding
    	to a leaf node (category without subcategories) has to trigger
    	the visibility of all the layers on the route to the layer
    	under the mouse pointer, and only of that layers,
    	while all the others have to be hidden.
    	This rule implies also that, if the mouse pointer exits from
    	a link corresponding to a non-leaf node and goes over a link
    	corresponding to a leaf node, then the "highest level" layer
    	among the visible ones will become hidden.
    	For a leaf node which is a root node's child, this rule simply
    	implies a shutdown().

    Useful hints
    ------------

    The geometry and the appearance of the menu is determined by
    parameters chosen invoking suited methods (refer to the class
    implementation in layersmenu.inc.php3) and by the HTML templates,
    provided in the "templates" directory.

    At the end of the parse_common() method (layersmenu.inc.php3)
    there is a commented out "if" block to handle the root node's children
    differently from children with hierarchical level > 1.
    This is intended as an alternative that is useful if you want
    to associate links only to leaf nodes, i.e. when non-leaf subcategories
    are intended to be empty (you are associating products only to leaf
    subcategories) and, hence, it is unuseful to visit them.

    It has been decided to add to each layer a title, corresponding
    to the name of the father node, because there is not a strict
    visual correspondence between a given layer and its "father link",
    but this correspondence may become more evident if the layer
    has a title recalling the "father".

    When the mouse passes over a link corresponding to a non leaf node,
    the starting ordinate of the layer to be popped up is set to the
    vertical coordinate of the link minus an offset (unless the size
    of the browsing window imposes some "wrapping"); such offset is chosen
    when invoking the new_*_menu() method.

    Alas, Netscape 4 is not able to return the vertical coordinate
    of the link by relying on the DOM tree; hence, for Netscape 4,
    such coordinate is estimated (with very, very good accuracy) through
    the vertical coordinate that the pointer has when it triggers
    the onmouseover event; that's why the vertical coordinate of the
    mouse pointer position is continuously detected through a portion
    of JavaScript code specifically devoted to Netscape 4.
    A threshold for the triggering of the layer position is used too,
    to avoid flickering of the layer to continuous repositioning
    if the mouse is moved around the link.

    How do you detect if a node is a leaf?
    Well, with the tree items ordered according to a depth-first search,
    a node is a leaf if one of the following two conditions is true;
    - it is the last node of the tree;
    - it is not the last node of the tree, and the hierarchical level
      associated to the subsequent node is larger or equal to the current
      hierarchical level.
    It should be rather easy to become convinced of this statement
    considering the view corresponding to a completely expanded tree menu.

    --
    Marco Pratesi
    marco at telug dot it